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

问题描述 投票:0回答:13

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

  • 网络统计: 有没有办法将 netstat 输出与 python 集成?
python port netstat
13个回答
182
投票

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

它看起来像这样。

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

139
投票

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

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

52
投票

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

25
投票

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

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

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

    print psutil.net_connections()
    

它也适用于 Windows。

https://github.com/giampaolo/psutil


8
投票

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

from time import sleep
import socket, ipaddress, threading
from pprint import pprint

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:
        final[ip] = "EXCEPTION"
        
port = 22
for ip in ipaddress.IPv4Network('95.217.210.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)


sorted_ips = dict(sorted(final.items(), key=lambda item: tuple(map(int, item[0].split('.')))))

for ip, state in sorted_ips.items():
    print(ip, state)

现场演示


7
投票

我在这篇文章中找到了多种解决方案。但某些解决方案存在挂起问题或在端口未打开的情况下花费太多时间。请尝试以下解决方案:

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

5
投票

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

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
投票

基于 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
投票

刚刚在 mrjandro 的解决方案中添加了一些改进,例如自动资源管理(确保打开的套接字也被关闭)、处理超时、消除简单的连接错误/超时以及打印结果:

import socket
from contextlib import closing

hosts = ["host1", "host2", "host3"]
port = 22
timeout_in_seconds = 2

hosts_with_opened_port = []
hosts_with_closed_port = []
hosts_with_errors = []


def check_port(host, port, timeout_in_seconds):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout_in_seconds)
    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
        try:
            result = sock.connect_ex((host, port))
            if result == 0:
                print("Port {} is *** OPEN *** on host: {}".format(port, host))
                hosts_with_opened_port.append(host)
            else:
                print("Port {} is not open on host: {}".format(port, host))
                hosts_with_closed_port.append(host)
        except socket.gaierror:
            print("Port {} check returns a network *** ERROR *** on host: {}".format(port, host))
            hosts_with_errors.append(host)


for host in hosts:
    check_port(host, port, timeout_in_seconds)

print("\nHosts with opened port:")
print(hosts_with_opened_port)
print("\nHosts with closed port:")
print(hosts_with_closed_port)
print("\nHosts with errors:")
print(hosts_with_errors)

4
投票

同意萨钦的观点。只是一个改进,使用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)
>>> 

3
投票

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

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


2
投票

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

这将在给定范围内找到一个随机端口:

import socket
import random 
from typing import Tuple

def find_listening_port(
    port_range:Tuple[int,int]=None, 
    host='', 
    socket_type='tcp', 
    default:int=None
) -> int:
    """Find an available listening port
    
    Arguments:
        port_range: Optional tuple of ports to randomly search, ``[min_port, max_port]``
            If omitted, then randomly search between ``[6000, 65534]``
        host: Host interface to search, if omitted then bind to all interfaces
        socket_type: The socket type, this should be ``tcp`` or ``udp``
        default: The port to try first before randomly searching the port range

    Returns:
        Available port for listening
    """
    def _test_port(host, port, socket_protocol):
        with socket.socket(socket.AF_INET, socket_protocol) as sock:
            try:
                sock.bind((host, port))
                if socket_type == 'tcp':
                    sock.listen(1)
                return port
            except:
                pass 

        return -1

    if port_range is None:
        port_range = (6000,65534)

    if socket_type == 'tcp':
        socket_protocol = socket.SOCK_STREAM
    elif socket_type == 'udp':
        socket_protocol = socket.SOCK_DGRAM
    else:
        raise Exception('Invalid socket_type argument, must be: tcp or udp')

    searched_ports = []
    if default is not None:
        port = _test_port(host, default, socket_protocol)
        if port != -1:
            return port
        searched_ports.append(default)

    for _ in range(100):
        port = random.randint(port_range[0], port_range[1])
        if port in searched_ports:
            continue 

        port = _test_port(host, port, socket_protocol)
        if port != -1:
            return port

        searched_ports.append(port)

    raise Exception(f'Failed to find {socket_type} listening port for host={host}')

使用示例:

# Find a TCP port,
# first check if port 80 is availble
port = find_listening_port(
    port_range=(4000, 60000),
    host='',
    socket_type='tcp',
    default=80
)
print(f'Available TCP port: {port}')
© www.soinside.com 2019 - 2024. All rights reserved.