2017-02-14 60 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:我试过自己试过了。谢谢 ! –