在不使用多线程的情况下Ping多个IP地址



我正在用java开发一个系统,用于ping IP地址并生成故障报告和其他一些统计信息。对于ping多个IP地址,我希望所有IP地址同时ping。使用多线程似乎是不可能的,因为我只有一个将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);
}
}
});
}                                        

感谢

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

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

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

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

您当前的代码从一个不是EDT的线程更新组件,这违反了Swings并发规则,有了swing Worker,您几乎可以免费解决这个问题(在某些情况下不使用EventQueue.invokeLater(...)(。

最后的一些建议:

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

    如果权限可以获得,否则它将尝试建立TCP连接在目标主机的端口7(Echo(上。

最新更新