【问题标题】:List of IP addresses/hostnames from local network in PythonPython中本地网络的IP地址/主机名列表
【发布时间】:2010-09-17 11:01:41
【问题描述】:

如何在 Python 中轻松获取本地网络的 IP 地址或主机名列表?

最好是多平台的,但需要先在 Mac OS X 上运行,然后其他的。

编辑:本地是指本地网络中的所有活动地址,例如192.168.xxx.xxx

因此,如果我的计算机(在本地网络中)的 IP 地址是 192.168.1.1,并且我连接了另外三台计算机,我希望它返回 IP 地址 192.168.1.2192.168.1.3、@987654325 @,可能还有他们的主机名。

【问题讨论】:

    标签: python networking


    【解决方案1】:

    如果“本地”是指在同一网段上,则必须执行以下步骤:

    1. 确定您自己的 IP 地址
    2. 确定您自己的网络掩码
    3. 确定网络范围
    4. 扫描所有地址(除了最低的,即您的网络地址,最高的,即您的广播地址)。
    5. 使用 DNS 的反向查找来确定响应扫描的 IP 地址的主机名。

    或者您可以让 Python 在外部执行 nmap 并将结果通过管道传回您的程序。

    【讨论】:

    • arp -a??? # 额外的评论空间被识别
    【解决方案2】:

    更新:脚本现在位于github

    我写了一个small python script,它利用了scapyarping()

    【讨论】:

      【解决方案3】:

      如果您知道可以使用的计算机名称:

      import socket
      IP1 = socket.gethostbyname(socket.gethostname()) # local IP adress of your computer
      IP2 = socket.gethostbyname('name_of_your_computer') # IP adress of remote computer
      

      否则,您将不得不扫描与本地计算机 (IP1) 具有相同掩码的所有 IP 地址,如另一个答案中所述。

      【讨论】:

      • 我如何获取我的计算机名称
      • socket.gethostname() 返回计算机名
      【解决方案4】:

      我从其他一些线程中收集了以下功能,它适用于我在 Ubuntu 中。

      import os
      import socket    
      import multiprocessing
      import subprocess
      import os
      
      
      def pinger(job_q, results_q):
          """
          Do Ping
          :param job_q:
          :param results_q:
          :return:
          """
          DEVNULL = open(os.devnull, 'w')
          while True:
      
              ip = job_q.get()
      
              if ip is None:
                  break
      
              try:
                  subprocess.check_call(['ping', '-c1', ip],
                                        stdout=DEVNULL)
                  results_q.put(ip)
              except:
                  pass
      
      
      def get_my_ip():
          """
          Find my IP address
          :return:
          """
          s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
          s.connect(("8.8.8.8", 80))
          ip = s.getsockname()[0]
          s.close()
          return ip
      
      
      def map_network(pool_size=255):
          """
          Maps the network
          :param pool_size: amount of parallel ping processes
          :return: list of valid ip addresses
          """
      
          ip_list = list()
      
          # get my IP and compose a base like 192.168.1.xxx
          ip_parts = get_my_ip().split('.')
          base_ip = ip_parts[0] + '.' + ip_parts[1] + '.' + ip_parts[2] + '.'
      
          # prepare the jobs queue
          jobs = multiprocessing.Queue()
          results = multiprocessing.Queue()
      
          pool = [multiprocessing.Process(target=pinger, args=(jobs, results)) for i in range(pool_size)]
      
          for p in pool:
              p.start()
      
          # cue hte ping processes
          for i in range(1, 255):
              jobs.put(base_ip + '{0}'.format(i))
      
          for p in pool:
              jobs.put(None)
      
          for p in pool:
              p.join()
      
          # collect he results
          while not results.empty():
              ip = results.get()
              ip_list.append(ip)
      
          return ip_list
      
      
      if __name__ == '__main__':
      
          print('Mapping...')
          lst = map_network()
          print(lst)
      

      【讨论】:

      • pinger() 中写着DEVNULL = open(os.devnull, 'w') 的那一行是什么?你不应该在函数结束时关闭os.devnull 以防止内存泄漏吗?
      • devnull 是重定向标准输出并像文件一样打印到它的控制台
      • Mapping... [] #这是我得到的输出。我只得到一个盒子。这有什么原因吗?
      • 你在linux上吗?上次我检查这在 Windows 上没有按预期工作
      【解决方案5】:

      对于 OSX(和 Linux),一个简单的解决方案是使用 os.popen 或 os.system 并运行 arp -a 命令。

      例如:

      devices = []
      for device in os.popen('arp -a'): devices.append(device)
      

      这将为您提供本地网络上的设备列表。

      【讨论】:

        【解决方案6】:

        我找到了这个network scanner in python article 并写了这个短代码。它做你想做的!但是,您确实需要知道设备的可访问端口。端口 22 是 ssh 标准和我正在使用的。我想你可以遍历所有端口。一些默认值是:

        linux: [20, 21, 22, 23, 25, 80, 111, 443, 445, 631, 993, 995]
        windows: [135, 137, 138, 139, 445]
        mac: [22, 445, 548, 631]
        
        import socket
        
        def connect(hostname, port):
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            socket.setdefaulttimeout(1)
            result = sock.connect_ex((hostname, port))
            sock.close()
            return result == 0
        
        for i in range(0,255):
            res = connect("192.168.1."+str(i), 22)
            if res:
                print("Device found at: ", "192.168.1."+str(i) + ":"+str(22))
        

        编辑 by TheLizzard:

        使用上面的代码并添加线程:

        from threading import Thread, Lock
        from time import perf_counter
        from sys import stderr
        from time import sleep
        import socket
        
        
        # I changed this from "192.168.1.%i" to "192.168.0.%i"
        BASE_IP = "192.168.0.%i"
        PORT = 80
        
        
        class Threader:
            """
            This is a class that calls a list of functions in a limited number of
            threads. It uses locks to make sure the data is thread safe.
            Usage:
                from time import sleep
        
                def function(i):
                    sleep(2)
                    with threader.print_lock:
                        print(i)
        
                threader = Threader(10) # The maximum number of threads = 10
                for i in range(20):
                    threader.append(function, i)
                threader.start()
                threader.join()
        
            This class also provides a lock called: `<Threader>.print_lock`
            """
            def __init__(self, threads=30):
                self.thread_lock = Lock()
                self.functions_lock = Lock()
                self.functions = []
                self.threads = []
                self.nthreads = threads
                self.running = True
                self.print_lock = Lock()
        
            def stop(self) -> None:
                # Signal all worker threads to stop
                self.running = False
        
            def append(self, function, *args) -> None:
                # Add the function to a list of functions to be run
                self.functions.append((function, args))
        
            def start(self) -> None:
                # Create a limited number of threads
                for i in range(self.nthreads):
                    thread = Thread(target=self.worker, daemon=True)
                    # We need to pass in `thread` as a parameter so we
                    # have to use `<threading.Thread>._args` like this:
                    thread._args = (thread, )
                    self.threads.append(thread)
                    thread.start()
        
            def join(self) -> None:
                # Joins the threads one by one until all of them are done.
                for thread in self.threads:
                    thread.join()
        
            def worker(self, thread:Thread) -> None:
                # While we are running and there are functions to call:
                while self.running and (len(self.functions) > 0):
                    # Get a function
                    with self.functions_lock:
                        function, args = self.functions.pop(0)
                    # Call that function
                    function(*args)
        
                # Remove the thread from the list of threads.
                # This may cause issues if the user calls `<Threader>.join()`
                # But I haven't seen this problem while testing/using it.
                with self.thread_lock:
                    self.threads.remove(thread)
        
        
        start = perf_counter()
        # I didn't need a timeout of 1 so I used 0.1
        socket.setdefaulttimeout(0.1)
        
        def connect(hostname, port):
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
                result = sock.connect_ex((hostname, port))
            with threader.print_lock:
                if result == 0:
                    stderr.write(f"[{perf_counter() - start:.5f}] Found {hostname}\n")
        
        threader = Threader(10)
        for i in range(255):
            threader.append(connect, BASE_IP%i, PORT)
        threader.start()
        threader.join()
        print(f"[{perf_counter() - start:.5f}] Done searching")
        input("Press enter to exit.\n? ")
        

        【讨论】:

        • 超级慢,我不认为这是一个可行的解决方案
        • @dlammy 我知道我有点晚了,但我添加了线程。现在它可以在不到 3 秒的时间内扫描所有 256 个可能的 IP。
        【解决方案7】:

        试试:

        import socket
        
        print ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])
        

        【讨论】:

        • 你能解释一下socket.gethostbyname_ex(socket.gethostname())的索引1处的数组吗?我不明白为什么它是空的。
        【解决方案8】:

        我已经完成了以下代码来获取 MAC 已知设备的 IP。这可以进行相应的修改,以通过一些字符串操作获得所有 IP。希望这会对你有所帮助。

        #running windows cmd line  statement and put output into a string
        cmd_out = os.popen("arp -a").read()
        line_arr = cmd_out.split('\n')
        line_count = len(line_arr)
        
        
        #search in all lines for ip
        for i in range(0, line_count):
            y = line_arr[i]
            z = y.find(mac_address)
        
            #if mac address is found then get the ip using regex matching
            if z > 0:
                ip_out= re.search('[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', y, re.M | re.I)
        

        【讨论】:

          【解决方案9】:

          我刚刚遇到了问题。我是这样解决的:

          import kthread #pip install kthread
          from time import sleep
          import subprocess
          
          def getips():
              ipadressen = {}
              def ping(ipadresse):
                  try:
                      outputcap = subprocess.run([f'ping', ipadresse, '-n', '1'], capture_output=True) #sends only one package, faster
                      ipadressen[ipadresse] = outputcap
                  except Exception as Fehler:
                      print(Fehler)
              t = [kthread.KThread(target = ping, name = f"ipgetter{ipend}", args=(f'192.168.0.{ipend}',)) for ipend in range(255)] #prepares threads
              [kk.start() for kk in t] #starts 255 threads
              while len(ipadressen) < 255:
                  print('Searching network')
                  sleep(.3)
              alldevices = []
              for key, item in ipadressen.items():
                  if not 'unreachable' in item.stdout.decode('utf-8') and 'failure' not in item.stdout.decode('utf-8'): #checks if there wasn't neither general failure nor 'unrechable host'
                      alldevices.append(key)
              return alldevices
          
          allips = getips() #takes 1.5 seconds on my pc
          

          【讨论】:

            【解决方案10】:

            this question 中的一个答案可能会对您有所帮助。 python 似乎有一个与平台无关的版本,但我还没有尝试过。

            【讨论】:

            • 不,我不想要我的 IP 地址,我想要其他人。史蒂夫莫耶所说的,但有代码:)
            【解决方案11】:

            这里有一个小工具scanip,可以帮助你获取网络中所有的ip地址和对应的mac地址(适用于Linux)。

            https://github.com/vivkv/scanip

            【讨论】:

              猜你喜欢
              • 2015-11-18
              • 1970-01-01
              • 2014-02-26
              • 2014-05-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-04-12
              相关资源
              最近更新 更多