TWaver - 專注UI技術(shù)

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

          Swing版小小網(wǎng)管

          Posted on 2010-09-14 17:28 TWaver 閱讀(1861) 評(píng)論(1)  編輯  收藏

          BlogJava上不少朋友是做網(wǎng)管系統(tǒng)的。一個(gè)典型的網(wǎng)絡(luò)管理系統(tǒng),需要具備FCAPS幾個(gè)標(biāo)準(zhǔn)模塊,而網(wǎng)絡(luò)的自動(dòng)發(fā)現(xiàn)和拓?fù)湔故臼呛诵闹弧:芏嗳瞬幌矚gJava的Swing,而本文就用一個(gè)很小很小的例子,來模擬一個(gè)小小的網(wǎng)絡(luò)管理程序,希望能給大家一點(diǎn)啟發(fā)。雖然很小,它卻可以完成一個(gè)簡(jiǎn)單的局域網(wǎng)自動(dòng)發(fā)現(xiàn)搜索、多線程、ICMP和SNMP的ping、節(jié)點(diǎn)的生成、拓?fù)涞恼故尽⒆詣?dòng)布局等功能。繼續(xù)改巴改巴也許還有點(diǎn)使用價(jià)值也未可知。

          如果不喜歡研究代碼,就當(dāng)它是一個(gè)趣味程序吧!你可以在公司的網(wǎng)絡(luò)里面搜索一把,把同事的機(jī)器都挖出來,看看你們公司的網(wǎng)絡(luò)結(jié)構(gòu)是怎樣的;如果喜歡研究代碼,可以看看相關(guān)SNMP、多線程和拓?fù)鋱D展示的部分,雖然很簡(jiǎn)單,就當(dāng)看肥皂劇消遣了。

          Ping和SNMP PING

          這個(gè)程序的自動(dòng)發(fā)現(xiàn)比較簡(jiǎn)單,就是對(duì)所在的網(wǎng)段進(jìn)行便利搜索。首先,獲得本機(jī)的網(wǎng)址以及所在的網(wǎng)段。例如,如果本機(jī)的地址是192.168.1.122,那么所在的網(wǎng)段自然就是192.168.1.0。然后,將這個(gè)網(wǎng)段中所有可能存在的IP地址進(jìn)行拆分,并通過多線程進(jìn)行任務(wù)分配,一個(gè)一個(gè)的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機(jī)器,有兩個(gè)做法。一個(gè)是傳統(tǒng)的調(diào)用命令行執(zhí)行Ping命令的做法。這種做法的好處是速度快,比較可靠。缺點(diǎn)是,不同的操作系統(tǒng),甚至Windows的不同版本,其執(zhí)行和返回結(jié)果格式都可能不同,造成跨平臺(tái)的不便以及代碼的啰嗦。第二個(gè)方法自然就是使用大家都熟知的Java 5提供的InetAddress的isReachable方法。這個(gè)方法本來應(yīng)當(dāng)很好,可是在實(shí)際使用中就會(huì)發(fā)現(xiàn),它不大靈光。超時(shí)時(shí)間設(shè)置短了吧,就ping不through;長(zhǎng)了把,又賊慢。網(wǎng)上不少人都反映和抱怨這個(gè)問題。仔細(xì)研究這個(gè)isReachable,會(huì)發(fā)現(xiàn)更多的問題。1、它不是線程安全的。也就是說,為了提高速度而使用多線程進(jìn)行多節(jié)點(diǎn)并行ping,會(huì)導(dǎo)致不安全的返回結(jié)果。這個(gè)問題挺致命。2、這個(gè)函數(shù)并非使用ICMP的ping,而是僅僅用TCP連一下7號(hào)端口而已:

           寫道

          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這個(gè)庫(kù)來完成。這個(gè)庫(kù)的地址是:

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

          不管怎么說,一個(gè)小小的ping還是挺麻煩。不過本例子由于僅僅是示例小程序,還是使用了isReachable方法,簡(jiǎn)化代碼。

          在ping通一個(gè)機(jī)器后,接下來再使用SNMP進(jìn)行ping。做過SNMP網(wǎng)管的朋友知道,所謂SNMP Ping其實(shí)就是用SNMP去get一個(gè)非常基本的OID看對(duì)方有無反應(yīng)。如果能夠返回?cái)?shù)據(jù),說明這是一個(gè)SNMP節(jié)點(diǎn),可以通過SNMP配合MIB庫(kù)去獲取更多的業(yè)務(wù)數(shù)據(jù)。例如磁盤、CPU、內(nèi)存、端口力量等等基本的信息,都有相關(guān)的SNMP MIB進(jìn)行定義。

          這個(gè)例子使用了Westhawk’s SNMP stack這個(gè)SNMP協(xié)議棧,一個(gè)輕量的、Java的、開源的、免費(fèi)的SNMP協(xié)議棧,實(shí)現(xiàn)了SNMPv1、SNMPv2c以及SNMPv3 (包括MD5和SHA1以及DES, AES加密算法)。地址在這里:

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

          使用Westhawk’s SNMP做一個(gè)簡(jiǎn)單的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,并假設(shè)community是public,超時(shí)時(shí)間1秒。獲取sysUpTime也就是設(shè)備啟動(dòng)時(shí)間。如果有返回,認(rèn)為節(jié)點(diǎn)存在且SNMP協(xié)議已啟動(dòng)。

          本例子就ping這么多。如果做一個(gè)真正的綜合設(shè)備網(wǎng)管,可以先獲得設(shè)備的標(biāo)識(shí)OID,判斷其設(shè)備廠商和型號(hào),然后加載對(duì)應(yīng)設(shè)備支持的MIB進(jìn)行復(fù)雜的監(jiān)控。

          多線程任務(wù)

          由于一個(gè)網(wǎng)段需要ping的地址很多,一個(gè)線程會(huì)很慢。所以這個(gè)例子中使用很多線程并發(fā)進(jìn)行。例如192.168.1.*里面有254個(gè)可能節(jié)點(diǎn),就用10個(gè)線程去分頭ping然后匯總。這個(gè)讓人想起網(wǎng)絡(luò)螞蟻。于是就做了一個(gè)類似網(wǎng)絡(luò)螞蟻的界面。


           

          其中,每個(gè)球是一個(gè)可能存在的節(jié)點(diǎn)地址。每個(gè)紅色的球是一個(gè)線程正在ping這個(gè)節(jié)點(diǎn)。灰色的球是已經(jīng)被ping過證明不存在或無法ping通的地址。綠色球是已經(jīng)ping通,存在的節(jié)點(diǎn)。

          通過調(diào)節(jié)線程的數(shù)量,可以掌握網(wǎng)絡(luò)發(fā)現(xiàn)的速度。一般這254個(gè)節(jié)點(diǎn),可以在30秒到60秒內(nèi)完成。

          拓?fù)涑尸F(xiàn)

          拓?fù)涑尸F(xiàn)用TWaver就行了。每次發(fā)現(xiàn)一個(gè)存在的節(jié)點(diǎn),往Network中new一個(gè)Node,設(shè)置一個(gè)圖標(biāo)即可。同時(shí),在網(wǎng)段節(jié)點(diǎn)(一個(gè)云形圖標(biāo)的節(jié)點(diǎn))和計(jì)算機(jī)節(jié)點(diǎn)創(chuàng)建一個(gè)連線。

          同時(shí),把拓?fù)鋱Dnetwork組件的彈簧布局打開。這樣,每次節(jié)點(diǎn)加入,都會(huì)像彈簧一樣被自動(dòng)布局到合適的位置,比較動(dòng)感、有視覺效果。 

          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通,我們?cè)诠?jié)點(diǎn)上就顯示一個(gè)windows圖標(biāo);如果snmp能ping通,再顯示一個(gè)齒輪的圖標(biāo)。顯示效果如下: 


           

          顯示圖標(biāo)的代碼很簡(jiǎn)單: 

          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”的命令來查看一個(gè)機(jī)器的共享信息。我們做一個(gè)右鍵菜單,將執(zhí)行命令結(jié)果顯示出來: 


           

          顯示結(jié)果如下: 
           

            

          結(jié)果顯示,這臺(tái)test計(jì)算機(jī)上有“move”、“SharedDocs”兩個(gè)共享目錄,以及三個(gè)共享打印機(jī)。實(shí)現(xiàn)的代碼如下:

           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    //可以用這兩行代碼來測(cè)試test機(jī)器的返回結(jié)果。
          71    public static void main(String[] args) {
          72        String result = executeCommand("net view <a>\\\\test</a>");
          73        System.out.println(result);
          74    }

          75}

          76

          鏈路探測(cè)與告警 

          在所有的節(jié)點(diǎn)被探索結(jié)束并放入界面后,我們可以起一個(gè)線程,周期性對(duì)每個(gè)節(jié)點(diǎn)進(jìn)行ping。一旦無法ping通,生成告警,顯示在拓?fù)鋱D中。 

           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

          將告警放置在一個(gè)告警表格中: 

           同時(shí),讓告警表和拓?fù)鋱D共享一個(gè)DataBox,于是告警就會(huì)在拓?fù)渲酗@示:


           
           

          最終效果以及源代碼下載 

          這是用這個(gè)小程序探索我們辦公室的網(wǎng)絡(luò)結(jié)構(gòu)。你的呢?也可以發(fā)上來看看! 


           
           


          源代碼、第三方lib包、可執(zhí)行包、run.bat都在附件中,請(qǐng)大家自行下載。請(qǐng)確保安裝了JAVA 6。解壓后雙擊run.bat即可。在彈出的對(duì)話框中點(diǎn)擊start按鈕即可進(jìn)行網(wǎng)絡(luò)自動(dòng)發(fā)現(xiàn)。 

          源代碼和可執(zhí)行文件點(diǎn)擊下載

          snmp_demo.zip

          GOOD LUCK & HAVE FUN!


          評(píng)論

          # re: Swing版小小網(wǎng)管  回復(fù)  更多評(píng)論   

          2010-09-21 10:49 by asdtiang
          標(biāo)記學(xué)習(xí)下

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 惠东县| 三原县| 长阳| 海口市| 梅河口市| 滨州市| 潞西市| 泽普县| 奉节县| 银川市| 扎赉特旗| 修武县| 江北区| 东乡县| 江陵县| 龙门县| 营山县| 丘北县| 来凤县| 诏安县| 翁牛特旗| 怀柔区| 大关县| 光山县| 旅游| 长寿区| 永丰县| 花莲县| 抚州市| 乳源| 彭泽县| 宝鸡市| 阳泉市| 吉安县| 盐津县| 望谟县| 白朗县| 湄潭县| 南木林县| 宕昌县| 吴桥县|