2017-02-14 59 views
0

我正在寫一個IP掃描儀應用程序和過程是需要長時間因此,我在使用GUI 回現場服務執行,如:如何從Swing worker運行服務執行程序?

public static List<Future<String>> checkThisIP(String ipStart, String ipEnd) throws UnknownHostException { 
    final ExecutorService es = Executors.newFixedThreadPool(10); 
    final List<Future<String>> futures = new ArrayList<>(); 
    String ipStringStart; 
    String ipStringEnd; 
    String targetIpString; 
    //my update 
    ipStringStart = ipStart.substring(ipStart.lastIndexOf(".") + 1, ipStart.length()); 
    ipStringEnd = ipEnd.substring(ipEnd.lastIndexOf(".") + 1, ipEnd.length()); 
    targetIpString = ipStart.substring(0, ipStart.lastIndexOf(".") + 1); 
    if (!ipStart.equals(ipEnd)) { 
     for (int i = Integer.parseInt(ipStringStart); i <= Integer.parseInt(ipStringEnd); i++) { 
      String currentIp = targetIpString + i; 
      futures.add(runPingScan(es, currentIp)); 
     } 
    } else { 
     futures.add(runPingScan(es, ipStart)); 
    } 
    es.shutdown(); 
    return futures; 
} 


public static Future<String> runPingScan(final ExecutorService es, final String ip) { 
    return es.submit(new Callable<String>() { 
     @Override 
     public String call() { 
      String returnMe = ""; 
      //custom ping class 
      Ping p = new Ping(); 
      //send message 
      p.SendReply(ip); 
      //IsReachable returns ture or false 
      if(p.IsReachable()){ 
       returnMe=ip; 
      } 
      return returnMe; 
      } 

    }); 
} 

這是使用的JButton原laggy代碼預製行動:

// scan result is Future list returned from service executor 
    List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText()); 
        for (final Future<String> f : scanResult) { 
         try { 
          ip = f.get(); 
          if (!ip.equals("")) { 
           arp ARP = new arp(); 
           PortScan openPort = new PortScan(); 
           IP ipClass = new IP(); 
           mac = ARP.getMac(ip); 
           manufacturer = ARP.getOUI(mac); 
           ports = openPort.checkIpForPorts(ip); 
           hostname = ipClass.hostname(ip); 
           title = ipClass.htmlTitle(ip); 
           Object[] data = {ip, mac, manufacturer, ports, hostname, title}; 
           tableModel.addRow(data); 
          } 

          if (jFormattedTextField1.getText().equals(jFormattedTextField2.getText()) && ip.equals("")) { 
           JOptionPane.showMessageDialog(null, "<html>Can not ping the address ! <br> Server might be protected by <b>WAF</b>.</html>", "Alert", HEIGHT); 
          } 
         } catch (Exception ex) { 
          Logger.getLogger(gui.class.getName()).log(Level.SEVERE, null, ex); 
         } 
        } 

運行這段代碼是好的,但是當我將其連接到開始掃描按鈕的GUI滯後,我一派,想通了使用搖擺工人。當我單獨實現了swing工作者的時候,它並沒有實現併發性,而且當我實現了gui仍然滯後時。無論如何,我的問題是讓按鈕(Swing worker)調用服務執行程序來執行其他進程嗎?

回答

1

我設法解決了我的問題,通過實施擺動工作人員和功能在底層做將啓動服務執行者的新線程,並防止滯後。

//The actionpreformed by the button 
    SwingWorker worker = new SwingWorker<Void, Void>() { 
      @Override 
     // All actions are done this method 
      protected Void doInBackground() throws Exception { 
       String ip = ""; 
       String mac = ""; 
       String manufacturer = ""; 
       String ports = ""; 
       String hostname = ""; 
       String title = ""; 
       tableModel.setRowCount(0); 
       PingScan p = new PingScan(); 
       List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText()); 
       for (final Future<String> f : scanResult) { 
        try { 
         ip = f.get(); 
         if (!ip.equals("")) { 
          arp ARP = new arp(); 
          PortScan openPort = new PortScan(); 
          IP ipClass = new IP(); 
          mac = ARP.getMac(ip); 
          manufacturer = ARP.getOUI(mac); 
          ports = openPort.checkIpForPorts(ip); 
          hostname = ipClass.hostname(ip); 
          title = ipClass.htmlTitle(ip); 
          Object[] data = {ip, mac, manufacturer, ports, hostname, title}; 
          tableModel.addRow(data); 
         } 
        } catch (Exception e) { 
         System.out.println(e.getMessage()); 
        } 
       } 
       return null; 
      } 
     }; 
    worker.execute(); 
1

當我單獨實現了swing worker時,它會導致併發性並且當我實現gui時仍然滯後。

有兩件事情,在這裏做:

  • 在多個線程將自己的平檢查

    • 分割你的任務分解成獨立的子任務
    • 跑分中的任務線程池
    • 收集結果
  • 從事件剝離整個操作dispach線程

    • 註冊用戶操作(點擊,按鍵),得到的文本字段中的數據,建立任務EDT
    • 更新之外
    • 運行任務GUI中,顯示結果

你與ExecutorService做的第一部分,對索姆e你的代碼。第二部分沒有在你的代碼中完成,所以美國東部時間將阻止整個操作完成,使你的gui滯後。

你需要這個代碼移到擺動工人,它運行在執行任務:

List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText()); 
       for (final Future<String> f : scanResult) { 
        try { 
         [...] // this is where the thread blocks, making your ui lag if it's the EDT 
         Object[] data = {ip, mac, manufacturer, ports, hostname, title}; 

首先,將所有阻止代碼被執行程序的線程池進行處理

public static Future<Object[]> runPingScan(final ExecutorService es, final String ip) { 
    return es.submit(new Callable<Object[]>() { 
     @Override 
     public Object[] call() { 
      //custom ping class 
      Ping p = new Ping(); 
      //send message 
      p.SendReply(ip); 
      //IsReachable returns ture or false 
      if(p.IsReachable()){ 
       [...] // other blocking code 
       return {ip, mac, manufacturer, ports, hostname, title}; 
      } else { 
       // special case, use null values or throw an exception 
      } 
     } 
    }); 
} 

然後你可以使用Simple Background Tasks教程代碼分離從EDT整個事情:

SwingWorker worker = new SwingWorker<List<Object[]>, Void>() { 
    public List<Object[]> doInBackground() { 
     // -- this will run in another thread -- 
     // submit ping checks to the executor 
     List<Future<Object[]>> scanResult = [...] 
     // get results, put them in a list, return it 
     List<Object[]> result = new ArrayList<>(); 
     for(Future<Object[]> f : scanResult) { 
      result.add(f.get()); // blocking happens here, outside of the EDT 
     } 
     return result; 
    } 

    public void done() { 
     // -- this will run in the EDT -- 
     // get() the list created above 
     // display the result in the gui 
     for(Object[] data : get()) { 
      tableModel.addRow(data); 
     } 
    } 
}; 

這裏沒有包含什麼特殊情況,比如失敗的ping檢查,您需要以某種方式處理它們。當調用f.get()時,從您的可調用對象中拋出的每個異常都會被重新拋出,並被ExecutionException包裝。對那些特殊情況使用它可能是你最好的選擇。

+0

感謝您的解釋+1。請注意,Swingworker的第一個參數應該是List >,我試過了你的答案,但我面臨同樣的滯後。看看我的回答,我只使用了swingworker函數** doInBackground()**來調用使用** service executor **(Lag cause)的函數,而沒有其他的swingfunction函數。 –

+0

第一個類型參數定義由'doInBackground'創建的數據,稍後通過調用'get'獲取數據。它只是一個字符串列表,不需要未來,因爲所有的ping檢查都已經完成。如果你在'doInBackground'內部做了所有的事情,確保你的模型正確地處理了gui更新(即'invokeLater'),因爲Swing不是線程安全的,任何接觸它的組件都應該從EDT開始。 – duckstep

+0

據我所知,字符串列表不能取List >。 'List > scanResult = p.checkThisIP(ip1,ip2); //該函數返回Future列表''所以如果我們想從'doInbackground()'返回該列表,那麼第一個參數應該是'>'。 P.S:我試過自己試過了。謝謝 ! –