TWaver - 專注UI技術

          http://twaver.servasoft.com/
          posts - 171, comments - 191, trackbacks - 0, articles - 2
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          Swing版小小網管

          Posted on 2010-09-14 17:28 TWaver 閱讀(1861) 評論(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
          標記學習下

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 体育| 边坝县| 镇巴县| 噶尔县| 甘德县| 常山县| 运城市| 江川县| 和政县| 平乡县| 进贤县| 富阳市| 池州市| 石泉县| 宣威市| 津南区| 古浪县| 仲巴县| 遂平县| 会理县| 开平市| 兴义市| 休宁县| 科技| 江安县| 山西省| 鹤山市| 广德县| 炉霍县| 额尔古纳市| 崇明县| 墨江| 黄梅县| 大新县| 石景山区| 台中市| 聊城市| 新闻| 隆德县| 大城县| 昔阳县|