1. 程式人生 > >Android 單執行緒也能極速重新整理並獲取區域網裝置(IP+MAC)資訊, 從4分30S 優化到 0.150S 不是夢

Android 單執行緒也能極速重新整理並獲取區域網裝置(IP+MAC)資訊, 從4分30S 優化到 0.150S 不是夢

            提前說明,Android 獲取區域網線上裝置的大概原理是:先去檢測某ip是否能通訊,然後去 /proc/net/arp 檔案(簡稱arp檔案)下讀取裡面正確的mac 與 ip 。

            最近產品又提需求了,要顯示當前區域網所在的裝置數量以及相關IP和mac資訊,心裡YY一笑,這種功能太簡單,

以前也研究過,只是方法(ping)比較耗時,我就把這情況告訴了產品,建議加個正在獲取的效果,產品否決,獲取過程

不能超過3s,話說用Ping方法在3s內要拿到結果,我得開幾十個執行緒才行吧,果斷放棄了這個想法,畢竟不是PC應用,

     先上一個ping的方法

   private void pingIp(String ip){
        try {
            java.lang.Process process = Runtime.getRuntime().exec("ping -c 1 -w 10 " + ip);
            process.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
          這就是ping方法 在單執行緒下,從 ip尾段 2~254 全部ping完,最少也要4分多,waitFor()方法是耗時的,它需要等待ping的響

應結果,響應完全部後還是要去讀arp檔案,是不是覺得這個流程有點奇怪,我為何要等他響應?等你響應完,從響應結果也拿

不到有價值的資訊,所以得想辦法不要這個響應過程。 那麼問題來了,你發ping出去,又不想要等響應,這個ping能實現?我

從ping的help中看了下其他附帶屬性,貌似沒有能達到這種結果的做法。

          後來重新想了下Android的儲存線上裝置資訊的原理,它是先和其他IP通訊,如果要通訊的那個IP正常響應,那就儲存對方的信

息到該檔案,下次再和該IP通訊時,就能快速地通過該資訊去找到這個要通訊的裝置了,這整個過程和應用層無關,這就涉及到計算

機網路知識了,小編了解不是很多,為了不誤導大家,所以具體網路層這塊還是自己去了解吧,回到主題,既然與我們應用層無關,

那麼我們是不是可以對某個IP發一個訊息,然後坐等網路層處理,我們不管這事情了呢,說到這裡,你是不是想到了什麼?不錯,就

是UDP,直接向某IP地址發訊息包過去(反正我發給你了,我可不管了) ,上程式碼

                DatagramPacket dp = new DatagramPacket(new byte[0], 0, 0);
                DatagramSocket socket = new DatagramSocket();
                int position = 2;
                while (position < 255) {
                    dp.setAddress(InetAddress.getByName("192.168.1." + String.valueOf(position)));
                    socket.send(dp);
                }
                socket.close();
           直接向尾段為 2~254 的IP發個訊息包過去,為了保證快速傳送,所以這個訊息包大小就為0,有小白可能就疑惑了,你這用的

是埠啊,你這訊息要發給誰啊,這也只能說去了解下計算機網路知識和使用埠的含義,粗糙得解釋,埠主要是為了區分一個IP

地址的其他socket或者說應用,所以說可以不考慮埠,訊息我發到該IP地址了,說明能通訊,只是有沒有這個埠的socket或應用

來接收,就不關我的事了。

          有人可能就直接用上面的方法去測試,不要急,先看下去,否則你會回來罵我的,說好的極速呢、0.150s呢,為何我的總是在

3.2s左右,你這不是騙我嗎,我沒有騙你,只是你太心急了而已,如果你細心除錯上面的程式碼或者看他傳送的時間,你就會發現,在

發訊息到尾段 236~239的IP時候(可能是其他區間),在某個IP傳送完訊息後出現停頓2s左右後才繼續發,這是什麼原因?這裡我只

猜測DatagramSocket 可能有一個排隊的現象(只是猜測,如果你知道具體原因,可以留言),直接上解決方法:

                DatagramPacket dp = new DatagramPacket(new byte[0], 0, 0);
                DatagramSocket socket = new DatagramSocket();
                int position = 2;
                while (position < 255) {
                    dp.setAddress(InetAddress.getByName("192.168.1." + String.valueOf(position)));
                    socket.send(dp);
                    position++;
                    if (position == 125) {//分兩段掉包,一次性發的話,達到236左右,會耗時3秒左右再往下發
                        socket.close();
                        socket = new DatagramSocket();
                    }
                }
                socket.close();
    

        解釋已經寫在上面程式碼塊了。跑完之後,再去讀arp檔案後就可以了,小編測試過,從發完包到過濾讀取arp資訊,平均耗時0.150s

左右,但是也會出現發完全部包後arp檔案還是沒有更新的現象,這情況只能說網路層響應慢或者更新慢(個人除錯發現,基本不會出現

超過一秒才能讀到的情況),所以只能來個輪巡查詢

                AllUtils.initAreaIp(mContext);//這是發包的方法
                List<AreaDeviceBean> beans = new ArrayList<>();
                int sum = 0;
                while (beans.size() == 0 && sum < 10) {
                    beans.addAll(AllUtils.getAllCacheMac(mLocalIP));//讀取arp內容方法
                    SystemClock.sleep(beans.size()>0?0:500);
                    sum++;
                }

       上面輪巡方法只提供參考,附帶Demo,小編辛苦打字,如果對你有幫助,請點個贊好嗎,如果有錯,請留言指出!