使用Python檢測局域網內IP地址使用情況


來源:https://www.cnblogs.com/donlin-zhang/p/6812675.html

 

在測試環境搭建的過程中,經常需要給服務器分配靜態IP地址,由於不清楚當前局域網內部哪些IP地址是空閑的,所以經常需要一個一個的去試,才能找到一個可用的IP。在之前的一家公司工作的時候,用到過一個檢測IP使用情況的工具,但是屬於內部工具,無法獲取到。於是乎便想,何不自己開發一個呢?

  說做便做,開發環境使用的是Python3.6+PyQt5. 如果你的環境不一樣,可能會運行失敗。

  源碼地址:https://github.com/LuckyDL/easyPing--python3.6

  1、界面設計

  界面用QtDesigner來畫的,先來一張原型圖如下,每次只能測試一個網段的IP占用情況,0-255個小窗格用來顯示IP地址的使用情況,默認為灰色,程序執行后,IP地址已使用的顯示綠色,IP地址未被使用的顯示紅色。

  

  做界面的時候,255個小窗格畫起來實在是要人命,於是就僅畫出了窗口框架,將UI文件轉成Python源碼后,自己手動編寫代碼來實現255窗格布局。代碼片段如下:

復制代碼
     self.gridlayout = QtWidgets.QGridLayout(self.widget1)
        self.gridlayout.setContentsMargins(0, 0, 0, 0)
        self.gridlayout.setObjectName("gridlayout")
        self.gridlayout.setSpacing(7)

        self.label_list = []
        list_index = 0
        for i in range(1, 17):
            for j in range(1, 17):
                label = QtWidgets.QLabel(self.widget1)
                label.setMinimumSize(QtCore.QSize(32, 15))
                label.setStyleSheet("")
                label.setAlignment(QtCore.Qt.AlignCenter)
                label.setText(QtCore.QCoreApplication.translate("MyPing", str(list_index)))
                self.label_list.append(label)
                self.gridlayout.addWidget(label, i-1, j-1, 1, 1)
                list_index += 1
復制代碼

 

  2、ping功能實現

  ping的實現方法有多種,最常用的當然是通過調用系統自帶的ping功能來實現。

  Python來執行系統命令的方式有os.system(), os.popen(), subprocess等方法,在Python3.6的手冊中表明,subprocess模塊是用來替代os.system等函數的。因此我們也使用subprocess模塊來調用ping

  python3.5中,subprocess增加了一個run函數,run函數創建有一個子進程來運行需要執行的命令,返回一個CompletedProcess實例,該函數基本上可以處理所有的應用場景,run是對subprocess.Popen的一層封裝。

       python3.5以下可以使用subprocess.call(), subprocess.check_call()等函數來實現相同的功能,具體可查閱Python手冊

復制代碼
def get_ping_result(self, ip):
    '''
    檢查對應的IP是否被占用
    '''
    cmd_str = "ping {0} -n 1 -w 600".format(ip)
    DETACHED_PROCESS = 0x00000008   # 不創建cmd窗口
    try:
        subprocess.run(cmd_str, creationflags=DETACHED_PROCESS, check=True)  # 僅用於windows系統
    except subprocess.CalledProcessError as err:
        self._ping_signal.emit(False, ip)
    else:
        self._ping_signal.emit(True, ip)
復制代碼

    說明:

  在默認情況下,使用subprocess.run()執行ping命令的時候,會彈出一個cmd窗口,當256個線程一起運行的時候,滿屏的窗口,想想都很酸爽。。。

       在windows系統下,可以傳入creationflags參數來使subprocess創建的子進程不生成console

  參考鏈接:https://stackoverflow.com/questions/7006238/how-do-i-hide-the-console-when-i-use-os-system-or-subprocess-call

  check參數為True時,函數將檢測執行結果是否為0(此處0表示執行成功),非零則拋出異常。

    3、多線程

        在使用pyqt進行GUI編程的時候,如果涉及到需要長時間后台運行的操作,一般需要使用多線程的方式,否則界面會阻塞,直到后台運行結束,造成程序卡死的假象。

       在本程序實現,要實現256個地址的ping操作,如果單線程操作,肯定半天也無法得到結果,因此我們為每一個IP地址分配一個線程,最多256線程並發運行,1~2秒的時間即可得到整個網段的IP地址占用情況

       多線程實現核心代碼如下:

復制代碼
def start_ping(self):
    '''
    啟動多線程
    '''
    self.reset_ui()
    startip = self.ui.startIP.text().split('.')
    endip = self.ui.endIP.text().split('.')
    tmp_ip = startip

    pthread_list = []
    for i in range(int(startip[3]), int(endip[3]) + 1):
        tmp_ip[3] = str(i)
        ip = '.'.join(tmp_ip)
        pthread_list.append(threading.Thread(target=self.get_ping_result, args=(ip,)))
    for item in pthread_list:
        item.setDaemon(True)
        item.start()
復制代碼

       

    子線程通過發射信號的方式來通知主程序執行結果,最終主程序根據運行結果渲染界面。

    全部源碼可到GitHub下載,鏈接見文章頭部。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM