java - 在不使用多线程的情况下 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);
}
}
});
}
谢谢
解决方案
在我看来,您反对多线程的论点是无效的:
- 您的要求是一次 ping 所有 IP 地址,这只是“并发”的另一个短语
- InetAddress.isReachable()以及调用和解析外部命令的输出具有阻塞性质
- 您的代码可以重构,因此多线程更容易实现
使用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 连接。
推荐阅读
- highcharts - 在highchart中添加点后获取ID
- laravel - laravel socialite 不能在实时服务器上工作,只能在本地机器上工作
- windows - Windows 中是否有“command -v”的等价物?
- react-native - cli.js require('@reat-native-community/cli') 找不到模块
- r - R - 图形交叉线
- python - 逻辑回归残差图/分布
- scala - 从不使用案例类的元组序列中创建具有数据框的数据集
- image - 如何从具有飞行时间相机的手机(Honor view20)拍摄的图像中访问深度信息?
- google-sheets - 如何识别列中的所有空白单元格,并将单独的选项卡同步到该列中每个空白区域的整行数据?
- amazon-web-services - 如何在 AWS 中创建快照例程