首页 > 解决方案 > 在不使用多线程的情况下 Ping 多个 IP 地址

问题描述

我正在开发一个用于 ping IP 地址并在 java 中生成故障报告和其他一些统计信息的系统。对于 ping 多个 IP 地址,我希望一次 ping 所有 IP 地址。使用多线程似乎是不可能的,因为我只有一种方法,将 IP 地址和文本区域显示为参数。我在 for 循环中有这个方法,每次迭代都会分配参数。

public Runnable runSystemCommand(String command ,JTextArea replyView ) throws FileNotFoundException, 
        IOException, ClassNotFoundException, SQLException, InterruptedException, ExecutionException {
    return new Runnable(){
        public void run(){
            PingDB db = new PingDB();
            try {
                db.openConnection();
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(ping_IP.class.getName()).log(Level.SEVERE, null, ex);
            }
           try{
               address = InetAddress.getByName(ip);
               status = address.isReachable(100000);

               //for (String ipAddress : ips){
               if (status){
                   Timestamp timeIn = new Timestamp(System.currentTimeMillis());
                   replyView.setText(replyView.getText()+ System.getProperty("line.separator")
                           +"Server reached at "+ timeIn);

               }else{
                   Timestamp tOut = new Timestamp(System.currentTimeMillis());
                  replyView.setText(replyView.getText()+ System.getProperty("line.separator")+
                          "Server timed out at "+tOut);

               }
               try {
                   p = Runtime.getRuntime().exec(command);

                   }catch (IOException ex) {
                   Logger.getLogger(ping_IP.class.getName()).log(Level.SEVERE, null, ex);
               }

                Scanner S = new Scanner(p.getInputStream());
                while (S.hasNextLine()) {
                    final String newText = S.nextLine();

                    if (newText.startsWith("Reply from ")||newText.startsWith("64 bytes of data")){

                        pingCount++;
                        //String sttm = "Insert into pingstatus Values ("+pingCount+",);";
                    }else{

                        timeOuts++;

                    }
                    EventQueue.invokeLater(new Runnable(){
                        public void run() {
                           //System.out.println(newText);
                           replyView.setText(replyView.getText()
                                    + System.getProperty("line.separator")
                                    + newText);
                        }
                    });

                }

           }catch (IOException e) {
               e.printStackTrace(); 

                               }
        }          
    };
}
Executor executor = Executors.newFixedThreadPool(1);


private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    //jButton is used to initiate the ping
    EventQueue.invokeLater(new Runnable() {
        public void run(){ 
            try {
                if (ips.size() == 1){

                    newPing.executor.execute(newPing.runSystemCommand("ping "+ips.get(0)+" -t",inputArea)); 

                }else{
                  //this is where the method above is called.  

                    for (String ip : ips) {
                        System.out.println(ip);
                        MultiView newView = new MultiView();
                        newView.setTitle("Pinging "+ip);
                        newView.setVisible(true);

                       newPing.executor.execute(newPing.runSystemCommand("ping "+ ip+" -t",newView.mView));

                    }
                }    
            } catch (FileNotFoundException ex) {
                Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException | ClassNotFoundException | SQLException | InterruptedException | ExecutionException ex) {
                Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
   });
}                                        

谢谢

标签: java

解决方案


在我看来,您反对多线程的论点是无效的:

  1. 您的要求是一次 ping 所有 IP 地址,这只是“并发”的另一个短语
  2. InetAddress.isReachable()以及调用和解析外部命令的输出具有阻塞性质
  3. 您的代码可以重构,因此多线程更容易实现

使用SwingWorkers将后台工作(ping)与更新 GUI 分开。其他优点是(请参阅教程):

  • 向调用线程提供结果
  • 取消,发现后台任务是否已经完成或被取消
  • 后台任务完成后更新 GUI(参见 SwingWorker.done()
  • 在 EDT 中更新 GUI 的中间结果(参见 SwingWorker.process(...)
  • 后台任务可以定义触发事件的绑定属性,从而在 EDT 上调用事件处理方法

您当前的代码从违反 Swings 并发规则的非 EDT 线程更新组件,使用 Swing 工作人员几乎可以免费解决此问题(EventQueue.invokeLater(...)在某些情况下无需像您那样使用。

最后的一些建议:

  • 你也可以在后台任务中使用执行器和线程池
  • 重构您的代码库,使其具有单一职责的类(处理外部程序输出、ping、...)
  • InetAddress.isReachable(...)您使用外部 ping 实用程序做了很多工作,是否值得删除一个?

    如果可以获得特权,典型的实现将使用 ICMP ECHO REQUEST,否则它将尝试在目标主机的端口 7 (Echo) 上建立 TCP 连接。


推荐阅读