使用Python识别监听端口

9 投票
6 回答
26455 浏览
提问于 2025-04-17 02:24

在把一些脚本从bash转到Python的时候,我发现很多地方用到了netstat -an这个命令来查看我们的服务是否在监听。虽然我知道可以用subprocess.call或者其他方法,比如popen,但我更想用一种更符合Python风格的方式,这样就不需要依赖我们正在使用的Unix环境。

根据我了解到的,socket模块应该有相关的功能,但我还没找到可以检查监听端口的东西。可能是我没有掌握某个简单的技巧,但到目前为止,我知道怎么连接一个socket,也能写出代码来告诉我连接失败了。但是,我还没有找到专门用来检查某个端口是否在监听的工具。

有没有什么好的建议呢?

6 个回答

4

在Linux系统中,我们可以使用strace工具来查看netstat -ln命令是如何读取和解析/proc文件系统中的各种信息的。

$ strace netstat -ln 2>&1| grep '/proc'
open("/proc/net/tcp", O_RDONLY)         = 3
open("/proc/net/tcp6", O_RDONLY)        = 3
open("/proc/net/udp", O_RDONLY)         = 3
open("/proc/net/udp6", O_RDONLY)        = 3
open("/proc/net/raw", O_RDONLY)         = 3
open("/proc/net/raw6", O_RDONLY)        = 3
open("/proc/net/unix", O_RDONLY)        = 3
open("/proc/net/ipx/socket", O_RDONLY)  = -1 ENOENT (No such file or directory)
open("/proc/net/ipx", O_RDONLY)         = -1 ENOENT (No such file or directory)
open("/proc/net/ax25", O_RDONLY)        = -1 ENOENT (No such file or directory)
open("/proc/net/x25", O_RDONLY)         = -1 ENOENT (No such file or directory)
open("/proc/net/x25", O_RDONLY)         = -1 ENOENT (No such file or directory)
open("/proc/net/nr", O_RDONLY)          = -1 ENOENT (No such file or directory)

所以你可以直接从Python中读取这些文件,提取你需要的数据。

$ cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8190 1 00000000 300 0 0 2 -1
   1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 6458 1 00000000 300 0 0 2 -1
   2: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 10425 1 00000000 300 0 0 2 -1
   3: 8D0BA8C0:8801 689255D1:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 1680975 1 00000000 24 4 16 6 -1
   4: 8D0BA8C0:D142 97E67D4A:01BB 06 00000000:00000000 03:000012E8 00000000     0        0 0 3 00000000
   5: 8D0BA8C0:D1A1 96E67D4A:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 1672130 1 00000000 24 4 18 5 -1
   6: 8D0BA8C0:D148 97E67D4A:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 1679875 1 00000000 24 4 20 5 -1

正在监听的套接字的远程地址会显示为00000000:0000。

地址和端口的组合是以十六进制表示的。你可以查看这个链接了解更多信息: * 如何将每个/proc/net/tcp条目与每个打开的套接字匹配?

你还可以和/proc//fd进行交叉参考。例如,sshd正在我的笔记本电脑上运行。

$ cat /var/run/sshd.pid
522

$ sudo ls -l /proc/522/fd
total 0
lrwx------ 1 root root 64 2011-09-15 21:32 0 -> /dev/null
lrwx------ 1 root root 64 2011-09-15 21:32 1 -> /dev/null
lrwx------ 1 root root 64 2011-09-15 21:32 2 -> /dev/null
lrwx------ 1 root root 64 2011-09-15 21:32 3 -> socket:[6456]
lrwx------ 1 root root 64 2011-09-15 21:32 4 -> socket:[6458]

套接字6456对应于/proc/net/tcp第二行中列出的inode 6458。

所以你确实可以从proc中获取所有这些信息,但你可能会发现自己在重新发明netstat -lntp这个命令。

6

我知道这个问题已经很久了,但我写这个是为了帮助初学者。如果你想找出你电脑上正在监听的端口,可以使用下面的代码。

from socket import *

Port = 0 #First port.
while Port <= 65535: #Port 65535 is last port you can access.
    try:
        try:
            Socket = socket(AF_INET, SOCK_STREAM, 0) #Create a socket.
        except:
            print("Error: Can't open socket!\n")    
            break #If can't open socket, exit the loop.
        Socket.connect(("127.0.0.1", Port)) #Try connect the port. If port is not listening, throws ConnectionRefusedError. 
        Connected = True
    except ConnectionRefusedError:
        Connected = False       
    finally:
        if(Connected and Port != Socket.getsockname()[1]): #If connected,
            print("{}:{} Open \n".format("127.0.0.1", Port)) #print port.
        Port = Port + 1 #Increase port.
        Socket.close() #Close socket.
12

你可以试着连接一下...

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = s.connect_ex(('127.0.0.1', 3306))

if result == 0:
    print('socket is open')
s.close()

撰写回答