【问题标题】:How to check if a network port is open?如何检查网络端口是否打开?
【发布时间】:2013-10-12 07:55:43
【问题描述】:

我如何知道某个端口是否在 linux ubuntu 上打开/关闭,而不是远程系统,使用 python? 如何在 python 中列出这些开放端口?

  • 网络统计: 有没有办法将 netstat 输出与 python 集成?

【问题讨论】:

    标签: python port netstat


    【解决方案1】:

    同意萨钦。只是一个改进,用connect_ex代替connect,这样可以避免try except

    >>> def port_check(ip_port):
    ...     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ...     s.settimeout(1)
    ...     return s.connect_ex(ip_port) == 0
    ... 
    >>> port_check(loc)
    True
    >>> port_check(loc_x)
    False
    >>> loc
    ('10.3.157.24', 6443)
    >>> 
    

    【讨论】:

      【解决方案2】:

      这是一个快速的多线程端口扫描器:

      from time import sleep
      import socket, ipaddress, threading
      
      max_threads = 50
      final = {}
      def check_port(ip, port):
          try:
              sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
              #sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
              socket.setdefaulttimeout(2.0) # seconds (float)
              result = sock.connect_ex((ip,port))
              if result == 0:
                  # print ("Port is open")
                  final[ip] = "OPEN"
              else:
                  # print ("Port is closed/filtered")
                  final[ip] = "CLOSED"
              sock.close()
          except:
              pass
      port = 80
      for ip in ipaddress.IPv4Network('192.168.1.0/24'): 
          threading.Thread(target=check_port, args=[str(ip), port]).start()
          #sleep(0.1)
      
          # limit the number of threads.
          while threading.active_count() > max_threads :
              sleep(1)
      
      print(final)
      

      Live Demo

      【讨论】:

        【解决方案3】:

        我在这篇文章中找到了多种解决方案。但有些解决方案存在挂起问题或在端口未打开的情况下需要很长时间。以下解决方案对我有用:

        import socket 
        
        def port_check(HOST):
           s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
           s.settimeout(2) #Timeout in case of port not open
           try:
              s.connect((HOST, 22)) #Port ,Here 22 is port 
              return True
           except:
              return False
        
        port_check("127.0.1.1")
        

        【讨论】:

          【解决方案4】:

          基于 Joe 提到的psutil 解决方案(仅适用于检查本地端口):

          import psutil
          1111 in [i.laddr.port for i in psutil.net_connections()]
          

          如果当前使用端口 1111,则返回 True

          psutil 不是 python stdlib 的一部分,所以你需要先pip install psutil。它还需要可用的 python 标头,所以你需要类似python-devel

          【讨论】:

            【解决方案5】:

            如果你只关心本地机器,你可以依赖 psutil 包。您可以:

            1. 检查特定 pid 使用的所有端口:

              proc = psutil.Process(pid)
              print proc.connections()
              
            2. 检查本地机器上使用的所有端口:

              print psutil.net_connections()
              

            它也适用于 Windows。

            https://github.com/giampaolo/psutil

            【讨论】:

            • 我通常会避免使用非标准库的解决方案,但是 gdi、psutil 应该只是在标准库中,它太重要了。
            • 第 2 部分正是我想要的,但 psutil 没有 net_connections() 函数。这在 Python 2 中不可用吗?我在 ubuntu 中。
            • @qwerty9967 不知道,我想您应该检查是否可以升级(如果您有 2.7 之前的版本或 psutil 包本身,请检查 python,最好使用 pip 而不是 apt-get/yum )
            【解决方案6】:

            您可以使用socket module 简单地检查端口是否打开。

            它看起来像这样。

            import socket
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            result = sock.connect_ex(('127.0.0.1',80))
            if result == 0:
               print "Port is open"
            else:
               print "Port is not open"
            sock.close()
            

            【讨论】:

            • 这有明显的缺点需要注意:简单地尝试检查连接可能1)由于防火墙或临时溢出而失败,2)在任何主动保护的情况下触发连接尝试的不需要的反应,3 ) 只会破坏日志和统计信息...通常首选使用专门的工具进行检查,因为 netstat 是首选。
            • @Netch - 当你在一个不想安装额外工具并且需要检查远程端口是否打开的盒子上时,这真的很方便。 . .
            • @WyattBarnett netstat 不是一个额外的工具(至少在 *nix 上):)
            • 我发布了另一个答案,简要说明了我将如何处理临时溢出问题,@Netch :)
            • 也适用于 Windows。
            【解决方案7】:

            请检查迈克尔的答案并投票。这是检查开放端口的正确方法。如果您正在开发服务或守护程序,则 Netstat 和其他工具没有任何用处。例如,我正在为工业网络创建 modbus TCP 服务器和客户端服务。服务可以监听任何端口,但问题是该端口是否开放?该程序将在不同的地方使用,我无法手动检查它们,所以我是这样做的:

            from contextlib import closing
            import socket
            class example:
                def __init__():
            
                   self.machine_ip = socket.gethostbyname(socket.gethostname())
                   self.ready:bool = self.check_socket()
            
                def check_socket(self)->bool:
                    result:bool = True
                    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
                    modbus_tcp_port:int = 502
                    if not sock.connect_ex((self.machine_ip, modbus_tcp_port)) == 0:
                        result = False
                    return result
            

            【讨论】:

              【解决方案8】:

              如果您探测 TCP 端口并打算监听它,最好实际调用 listen。使用tring 连接的方法不会“看到”已建立连接的客户端端口,因为没有人监听它。但是这些端口不能用来监听它。

              import socket
              
              
              def check_port(port, rais=True):
                  """ True -- it's possible to listen on this port for TCP/IPv4 or TCP/IPv6
                  connections. False -- otherwise.
                  """
                  try:
                      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                      sock.bind(('127.0.0.1', port))
                      sock.listen(5)
                      sock.close()
                      sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
                      sock.bind(('::1', port))
                      sock.listen(5)
                      sock.close()
                  except socket.error as e:
                      return False
                      if rais:
                          raise RuntimeError(
                              "The server is already running on port {0}".format(port))
                  return True
              

              【讨论】:

              • 使用像 5 这样的“幻数”而不加注释是不好的做法。根据文档,这个参数 socket.socket.listen(backlog) 是“系统将允许的未接受连接数”。目前尚不清楚为什么您的解决方案不适用于积压的“0”,只是为了测试套接字是否可用于侦听端点。 (P.S. 我更喜欢你的解决方案而不是实际尝试连接的解决方案)
              • 这就是我想要的。但是如果有人只是在寻找任何开放的端口,也许像stackoverflow.com/a/45690594/101923 所示绑定到端口0 更合适。
              【解决方案9】:

              刚刚在 mrjandro 的解决方案中添加了一个快速破解方法,以摆脱简单的连接错误/超时。

              您可以调整更改 max_error_count 变量值的阈值并添加任何类型的通知。

              import socket
              
              max_error_count = 10
              
              def increase_error_count():
                  # Quick hack to handle false Port not open errors 
                  with open('ErrorCount.log') as f:
                      for line in f:
                          error_count = line
                  error_count = int(error_count)
                  print "Error counter: " + str(error_count)
                  file = open('ErrorCount.log', 'w')
                  file.write(str(error_count + 1))
                  file.close()
                  if error_count == max_error_count:
                      # Send email, pushover, slack or do any other fancy stuff
                      print "Sending out notification"
                      # Reset error counter so it won't flood you with notifications
                      file = open('ErrorCount.log', 'w')
                      file.write('0')
                      file.close()
              
              sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
              sock.settimeout(2) 
              result = sock.connect_ex(('127.0.0.1',80))
              if result == 0:
                      print "Port is open"
              else:
                      print "Port is not open"
                      increase_error_count()
              

              在这里您可以找到兼容 Python 3 的版本(只是修复了打印语法):

              import socket
              
              max_error_count = 10
              
              def increase_error_count():
                  # Quick hack to handle false Port not open errors
                  with open('ErrorCount.log') as f:
                      for line in f:
                          error_count = line
                  error_count = int(error_count)
                  print ("Error counter: " + str(error_count))
                  file = open('ErrorCount.log', 'w')
                  file.write(str(error_count + 1))
                  file.close()
                  if error_count == max_error_count:
                      # Send email, pushover, slack or do any other fancy stuff
                      print ("Sending out notification")
                      # Reset error counter so it won't flood you with notifications
                      file = open('ErrorCount.log', 'w')
                      file.write('0')
                      file.close()
              
              sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
              sock.settimeout(2) 
              result = sock.connect_ex(('127.0.0.1',80))
              if result == 0:
                      print ("Port is open")
              else:
                      print ("Port is not open")
                      increase_error_count()
              

              【讨论】:

              • 您好!您只需要对其中的打印功能进行一些小的更改...检查我粘贴的新版本:) 例如,您可以轻松地将其更改为不将数据保存到日志文件中。
              【解决方案10】:

              对我来说,如果端口未打开,上述示例将挂起。第 4 行显示使用 settimeout 来防止挂起

              import socket
              
              sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
              sock.settimeout(2)                                      #2 Second Timeout
              result = sock.connect_ex(('127.0.0.1',80))
              if result == 0:
                print 'port OPEN'
              else:
                print 'port CLOSED, connect_ex returned: '+str(result)
              

              【讨论】:

                【解决方案11】:

                如果您想在更一般的上下文中使用它,您应该确保您打开的套接字也被关闭。所以检查应该更像这样:

                import socket
                from contextlib import closing
                
                def check_socket(host, port):
                    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
                        if sock.connect_ex((host, port)) == 0:
                            print "Port is open"
                        else:
                            print "Port is not open"
                

                【讨论】:

                • 因提及 Automatic Resource Management 而被投票赞成。更多人需要看到这个!
                • 嗨,迈克尔,感谢您的回复;一个问题,你为什么要使用connect_ex 而不是bind。我在 py3 和 mac 上使用 connect 或 connect_ex 的每一次尝试都失败并出现错误 61,然后自动为我的套接字分配一个端口,然后是错误 22。相反,bind 符合我的预期,如果返回端口是打开的,如果它在使用中就扔掉。我错过了什么吗?
                • @plumSemPy 我的答案是为 python2 编写的。在 python3 中,套接字已经作为上下文管理器工作。所以如果 bind 适合你,那就完美了。
                【解决方案12】:

                Netstat 工具只是解析一些 /proc 文件,例如 /proc/net/tcp 并将其与其他文件内容相结合。是的,它是高度特定于平台的,但对于仅限 Linux 的解决方案,您可以坚持使用它。 Linux 内核文档详细描述了这些文件,因此您可以在那里找到如何阅读它们。

                还请注意您的问题过于含糊,因为“端口”也可能表示串行端口(/dev/ttyS* 和类似物)、并行端口等;我已经重复使用另一个答案的理解,这是网络端口,但我会要求您更准确地提出您的问题。

                【讨论】:

                  猜你喜欢
                  • 2012-02-14
                  • 2012-08-03
                  • 1970-01-01
                  • 2014-12-04
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多