TWaver - 专注UI技术

http://twaver.servasoft.com/
posts - 171, comments - 191, trackbacks - 0, articles - 2
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Swing版小小网管

Posted on 2010-09-14 17:28 TWaver 阅读(1850) 评论(1)  编辑  收藏

BlogJava上不少朋友是做网管系统的。一个典型的网络管理系统,需要具备FCAPS几个标准模块,而网络的自动发现和拓扑展示是核心之一。很多人不喜欢Java的Swing,而本文就用一个很小很小的例子,来模拟一个小小的网络管理程序,希望能给大家一点启发。虽然很小,它却可以完成一个简单的局域网自动发现搜索、多线程、ICMP和SNMP的ping、节点的生成、拓扑的展示、自动布局等功能。继续改巴改巴也许还有点使用价值也未可知。

如果不喜欢研究代码,就当它是一个趣味程序吧!你可以在公司的网络里面搜索一把,把同事的机器都挖出来,看看你们公司的网络结构是怎样的;如果喜欢研究代码,可以看看相关SNMP、多线程和拓扑图展示的部分,虽然很简单,就当看肥皂剧消遣了。

Ping和SNMP PING

这个程序的自动发现比较简单,就是对所在的网段进行便利搜索。首先,获得本机的网址以及所在的网段。例如,如果本机的地址是192.168.1.122,那么所在的网段自然就是192.168.1.0。然后,将这个网段中所有可能存在的IP地址进行拆分,并通过多线程进行任务分配,一个一个的Ping。

 1public static boolean ping(String ip) {
 2        try {
 3            InetAddress ipaddress = InetAddress.getByName(ip);
 4            return ipaddress.isReachable(2000);
 5        }
 catch (Exception ex) {
 6            ex.printStackTrace();
 7            return false;
 8        }

 9    }

10

用Java来Ping机器,有两个做法。一个是传统的调用命令行执行Ping命令的做法。这种做法的好处是速度快,比较可靠。缺点是,不同的操作系统,甚至Windows的不同版本,其执行和返回结果格式都可能不同,造成跨平台的不便以及代码的啰嗦。第二个方法自然就是使用大家都熟知的Java 5提供的InetAddress的isReachable方法。这个方法本来应当很好,可是在实际使用中就会发现,它不大灵光。超时时间设置短了吧,就ping不through;长了把,又贼慢。网上不少人都反映和抱怨这个问题。仔细研究这个isReachable,会发现更多的问题。1、它不是线程安全的。也就是说,为了提高速度而使用多线程进行多节点并行ping,会导致不安全的返回结果。这个问题挺致命。2、这个函数并非使用ICMP的ping,而是仅仅用TCP连一下7号端口而已:

 写道

InetAddress.isReachable() doesn’t use ICMP, it just tries to open TCP port 7 at the target. You can use ICMP in Java with the JPCAP library if you can find it, but you can’t multithread it for reasons which are discussed above – basically, ICMP is not thread-safe

又慢又线程不安全就比较不爽了。还可以使用上面提到的JPCAP这个库来完成。这个库的地址是:

http://netresearch.ics.uci.edu/kfujii/jpcap/doc/

不管怎么说,一个小小的ping还是挺麻烦。不过本例子由于仅仅是示例小程序,还是使用了isReachable方法,简化代码。

在ping通一个机器后,接下来再使用SNMP进行ping。做过SNMP网管的朋友知道,所谓SNMP Ping其实就是用SNMP去get一个非常基本的OID看对方有无反应。如果能够返回数据,说明这是一个SNMP节点,可以通过SNMP配合MIB库去获取更多的业务数据。例如磁盘、CPU、内存、端口力量等等基本的信息,都有相关的SNMP MIB进行定义。

这个例子使用了Westhawk’s SNMP stack这个SNMP协议栈,一个轻量的、Java的、开源的、免费的SNMP协议栈,实现了SNMPv1、SNMPv2c以及SNMPv3 (包括MD5和SHA1以及DES, AES加密算法)。地址在这里:

http://snmp.westhawk.co.uk/

使用Westhawk’s SNMP做一个简单的get操作如下:

1
2SnmpContextv2c context = new SnmpContextv2c(ip, 161);
3context.setCommunity("public");
4BlockPdu pdu = new BlockPdu(context);
5pdu.setRetryIntervals(new int[] 1000 });
6String sysUpTime = "1.3.6.1.2.1.1.3.0";
7pdu.addOid(sysUpTime);
8Object result = pdu.getResponseVariable();

代码中用v2c,并假设community是public,超时时间1秒。获取sysUpTime也就是设备启动时间。如果有返回,认为节点存在且SNMP协议已启动。

本例子就ping这么多。如果做一个真正的综合设备网管,可以先获得设备的标识OID,判断其设备厂商和型号,然后加载对应设备支持的MIB进行复杂的监控。

多线程任务

由于一个网段需要ping的地址很多,一个线程会很慢。所以这个例子中使用很多线程并发进行。例如192.168.1.*里面有254个可能节点,就用10个线程去分头ping然后汇总。这个让人想起网络蚂蚁。于是就做了一个类似网络蚂蚁的界面。


 

其中,每个球是一个可能存在的节点地址。每个红色的球是一个线程正在ping这个节点。灰色的球是已经被ping过证明不存在或无法ping通的地址。绿色球是已经ping通,存在的节点。

通过调节线程的数量,可以掌握网络发现的速度。一般这254个节点,可以在30秒到60秒内完成。

拓扑呈现

拓扑呈现用TWaver就行了。每次发现一个存在的节点,往Network中new一个Node,设置一个图标即可。同时,在网段节点(一个云形图标的节点)和计算机节点创建一个连线。

同时,把拓扑图network组件的弹簧布局打开。这样,每次节点加入,都会像弹簧一样被自动布局到合适的位置,比较动感、有视觉效果。 

1network.getSpringLayouter().setMovableFilter(new MovableFilter() {
2    public boolean isMovable(Element element) {
3       return element != centerNode;
4    }

5}
);
6network.getSpringLayouter().start();
7network.getSpringLayouter().setLinkRepulsionFactor(2);

另外,一旦ping通,我们在节点上就显示一个windows图标;如果snmp能ping通,再显示一个齿轮的图标。显示效果如下: 


 

显示图标的代码很简单: 

1        ResizableNode node = new ResizableNode(ipaddress);
2        node.setImage("/demo/main/snmp/images/node.png");
3        node.addAttachment("winxp");
4        node.putAttachmentPosition(TWaverConst.POSITION_TOPLEFT);
5        if (snmpPingOK) {
6            node.addAttachment("snmp");
7        }

8

此外,可以通过windows的“net view hostname”的命令来查看一个机器的共享信息。我们做一个右键菜单,将执行命令结果显示出来: 


 

显示结果如下: 
 

  

结果显示,这台test计算机上有“move”、“SharedDocs”两个共享目录,以及三个共享打印机。实现的代码如下:

 1import java.io.*;
 2
 3import java.awt.*;
 4import java.awt.event.*;
 5import javax.swing.*;
 6
 7import twaver.*;
 8import twaver.network.*;
 9
10public class SnmpPopupMenuFactory implements PopupMenuFactory {
11
12    private TNetwork network = null;
13
14    public SnmpPopupMenuFactory(TNetwork network) {
15        this.network = network;
16    }

17
18    public JPopupMenu getPopupMenu(DataBoxSelectionModel dataBoxSelectionModel, Point point) {
19        if (network.getDataBox().getSelectionModel().size() == 1{
20            Element element = network.getDataBox().getSelectionModel().lastElement();
21            if (element instanceof ResizableNode) {
22                final Node node = (Node) element;
23
24                JPopupMenu menu = new JPopupMenu();
25                JMenuItem item = new JMenuItem("View this computer");
26                item.addActionListener(new ActionListener() {
27
28                    public void actionPerformed(ActionEvent e) {
29                        String result = executeCommand("net view <a>\\\\</a>" + node.getName());
30                        if (result != null && !result.trim().isEmpty()) {
31                            JOptionPane.showMessageDialog(network, result);
32                        }
 else {
33                            JOptionPane.showMessageDialog(network, "No information available.");
34                        }

35                    }

36                }
);
37                menu.add(item);
38
39                return menu;
40            }

41        }

42        return null;
43    }

44
45    private static String executeCommand(String command) {
46        try {
47            Process p = Runtime.getRuntime().exec(command);
48            InputStreamReader ir = new InputStreamReader(p.getInputStream());
49            LineNumberReader input = new LineNumberReader(ir);
50
51            String result = null;
52            String line = input.readLine();
53            while (line != null{
54                if (result == null{
55                    result = line;
56                }
 else {
57                    if (!line.trim().equalsIgnoreCase("")) {
58                        result = result + "\n" + line.trim();
59                    }

60                }

61                line = input.readLine();
62            }

63            return result;
64        }
 catch (IOException ex) {
65            ex.printStackTrace();
66        }

67        return null;
68    }

69
70    //可以用这两行代码来测试test机器的返回结果。
71    public static void main(String[] args) {
72        String result = executeCommand("net view <a>\\\\test</a>");
73        System.out.println(result);
74    }

75}

76

链路探测与告警 

在所有的节点被探索结束并放入界面后,我们可以起一个线程,周期性对每个节点进行ping。一旦无法ping通,生成告警,显示在拓扑图中。 

 1Thread linkCheckThread = new Thread() {
 2
 3            @Override
 4            public void run() {
 5                while (true{
 6                    try {
 7                        Thread.sleep(3000);
 8                        if (!network.getDataBox().isEmpty()) {
 9                            Collection elements = network.getDataBox().getAllElements();
10                            Iterator it = elements.iterator();
11                            while (it.hasNext()) {
12                                final Element element = (Element) it.next();
13                                if (element instanceof ResizableNode) {
14                                    final String ipaddress = element.getID().toString();
15                                    final boolean pingOK = ping(ipaddress);
16
17                                    SwingUtilities.invokeLater(new Runnable() {
18
19                                        public void run() {
20                                            Alarm alarm = new Alarm();
21                                            if (!pingOK) {
22                                                alarm.setAlarmSeverity(AlarmSeverity.CRITICAL);
23                                            }
 else {
24                                                if (element.getAlarmState().isEmpty()) {
25                                                    return;
26                                                }

27                                                alarm.setAlarmSeverity(AlarmSeverity.CLEARED);
28                                            }

29                                            alarm.setElementID(ipaddress);
30                                            alarm.setProbableCause(AlarmProbableCause.LINE_INTERFACE_FAILURE);
31                                            box.getAlarmModel().addAlarm(alarm);
32                                        }

33                                    }
);
34                                }

35                            }

36                        }

37                    }
 catch (InterruptedException ex) {
38                        ex.printStackTrace();
39                    }

40                }

41            }

42        }
;
43        linkCheckThread.start();
44    }
45

将告警放置在一个告警表格中: 

 同时,让告警表和拓扑图共享一个DataBox,于是告警就会在拓扑中显示:


 
 

最终效果以及源代码下载 

这是用这个小程序探索我们办公室的网络结构。你的呢?也可以发上来看看! 


 
 


源代码、第三方lib包、可执行包、run.bat都在附件中,请大家自行下载。请确保安装了JAVA 6。解压后双击run.bat即可。在弹出的对话框中点击start按钮即可进行网络自动发现。 

源代码和可执行文件点击下载

snmp_demo.zip

GOOD LUCK & HAVE FUN!


评论

# re: Swing版小小网管  回复  更多评论   

2010-09-21 10:49 by asdtiang
标记学习下

只有注册用户登录后才能发表评论。


网站导航: