如何检查Linux上的网络端口是否打开?


73

我如何使用python在Linux ubuntu而非远程系统上打开/关闭某个端口?如何在python中列出这些打开的端口?

  • Netstat:有没有办法将netstat输出与python集成?

Answers:


136

您可以使用套接字模块简单地检查端口是否打开。

它看起来像这样。

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()

12
这有明显的缺点,应注意:仅尝试检查连接可能是:1)由于防火墙或临时溢出而失败; 2)在任何有效保护的情况下,触发了不想要的连接尝试反应; 3)仅破坏了日志和统计信息。通常首选使用专用工具作为netstat进行检查。
Netch

5
@Netch-当您不想在盒子上安装额外的工具并且需要检查远程端口是否打开时,这真的很方便。。。
Wyatt Barnett 2014年

@WyattBarnett netstat不是一个额外的工具(至少在* nix上是这样的:)
Pitto

我发表了另一种答案与我会如何处理临时溢出问题,@Netch :)快速小额
Pitto

3
在Windows上也可以使用。
maciek's

89

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

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"

9
赞扬提及自动资源管理。更多的人需要看这个!
Blockost

嗨,迈克尔,感谢您的答复;一个问题,为什么要用connect_ex代替bind。我的所有尝试在py3和mac上使用connect或connect_ex的尝试均失败,并显示错误61,然后自动将端口分配给我的套接字,然后是err22。相反bind,,执行我期望的操作,如果端口是打开,如果正在使用则扔。我想念什么吗?
plumSemPy

1
@plumSemPy我的答案是为python2编写的。在python3中,套接字已经可以用作上下文管理器。因此,如果bind为您工作,那就太完美了。
迈克尔

36

对我来说,如果端口未打开,则上面的示例将挂起。第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)

20

如果只关心本地计算机,则可以依赖psutil软件包。您可以:

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

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

    print psutil.net_connections()
    

它也适用于Windows。

https://github.com/giampaolo/psutil


2
我通常会避免使用非stdlib解决方案,但是gdi,psutil应该只在stdlib中,它太当了。
ThorSummoner

第2部分正是我在寻找的东西,但是psutil没有net_connections()函数。这在Python 2中不可用吗?我在ubuntu。
qwerty9967

@ qwerty9967不知道,我想您应该检查是否可以升级(如果您具有2.7之前的版本或python或psutil软件包本身,最好使用python,最好使用pip而不是apt-get / yum)

3

如果您打算侦听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

2
不加注释地使用“ 5”这样的“魔术数字”是不好的做法。根据文档,此参数socket.socket.listen(backlog)是“系统允许的不可接受的连接数”。目前尚不清楚为什么您的解决方案不能与积压为0的项一起使用,只是为了测试套接字是否可以用于侦听端点。(PS我比实际尝试连接更喜欢您的解决方案)
Marvin

这就是我想要的。但是,如果有人只是在寻找任何打开的端口,则可能更合适的方法是将其绑定到端口0,如stackoverflow.com/a/45690594/101923中所示。
Tim Swast

2

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

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


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)

现场演示


1

刚刚添加到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()

嗨,您好!您只需要对其中的打印功能进行一些细微更改...检查我粘贴的新版本:)例如,您可以轻松更改它以不将数据保存到日志文件中。
皮托

1

请检查迈克尔的答案并投票。这是检查打开的端口的正确方法。如果您要开发服务或守护程序,则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

0

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

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

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

psutil 不是python stdlib的一部分,因此您需要 pip install psutil首先。它还需要python标头可用,因此您需要类似python-devel


0

在上面,我找到了多个解决方案。但是有些解决方案存在挂起问题,或者在打开端口的情况下花费很多时间。下面的解决方案对我有用:

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")

0

同意萨钦。只是一项改进,使用connect_ex而不是connect可以避免尝试,但

>>> def port_check(ip_port):
...     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
...     s.settimeout(1)
...     r = s.connect_ex(ip_port)
...     return r == 0
... 
>>> port_check(loc)
True
>>> port_check(loc_x)
False
>>> loc
('10.3.157.24', 6443)
>>> 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.