在Python中打开TCP端口

在Python中打开TCP端口,python,tcp,tcp-port,Python,Tcp,Tcp Port,我想在Python中获取localhost上任何随机打开的TCP端口。最简单的方法是什么?我当前的解决方案: def get_open_port(): import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("",0)) s.listen(1) port = s.getsockname()[1] s.clo

我想在Python中获取localhost上任何随机打开的TCP端口。最简单的方法是什么?

我当前的解决方案:

def get_open_port():
        import socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("",0))
        s.listen(1)
        port = s.getsockname()[1]
        s.close()
        return port

不是很好,也不是100%正确,但它现在可以工作。

我实际上在我的一个程序中使用了以下内容:

port = random.randint(10000,60000)
当然,这比您的代码更容易发生冲突。但我从来没有遇到过问题。关键是,在任何给定的时间,大多数编号较高的端口都没有被使用,如果您只是随机选择一个,那么与另一个进程发生冲突的可能性很小。如果您执行类似于您在回答中发布的解决方案的操作(打开一个套接字并获取其端口号),则几乎可以肯定端口不会发生冲突。因此,如果这是你只为自己使用的东西(而不是你将要向公众发布的东西),想想是否值得拿出一个真正的防弹解决方案。很可能这永远不会有什么不同


出于Marcelo Cantos对您的问题的评论的动机,我将补充说,在这种情况下,标准解决方案是将使用端口的进程绑定到它,然后与任何其他需要它的程序共享该信息。通常情况下,它会将包含端口号的临时文件写入文件系统中的某个标准位置。由于您正在使用的流程没有做到这一点,因此从某种意义上讲,您提出的任何解决方案都会有点麻烦。但是,如果它只是供您自己使用,那可能没问题。

这是我的版本,但是如果您指定端口范围,它并不是随机的。这也会受到比赛条件的影响,但是如果你需要提前知道港口,这是我知道的最好的方法

import socket
import errno
import contextlib

reserved_ports = set()

def get_open_port(lowest_port = 0, highest_port = None, bind_address = '', *socket_args, **socket_kwargs):
    if highest_port is None:
        highest_port = lowest_port + 100
    while lowest_port < highest_port:
        if lowest_port not in reserved_ports:
            try:
                with contextlib.closing(socket.socket(*socket_args, **socket_kwargs)) as my_socket:
                    my_socket.bind((bind_address, lowest_port))
                    this_port = my_socket.getsockname()[1]
                    reserved_ports.add(this_port)
                    return this_port
            except socket.error as error:
                if not error.errno == errno.EADDRINUSE:
                    raise
                assert not lowest_port == 0
                reserved_ports.add(lowest_port)
        lowest_port += 1
    raise Exception('Could not find open port')
导入套接字
输入错误号
导入上下文库
保留端口=设置()
def get_open_端口(最低_端口=0,最高_端口=无,绑定_地址=“”,*套接字参数,**套接字参数):
如果最高_端口为无:
最高_端口=最低_端口+100
最低\u端口<最高\u端口:
如果最低\u端口不在保留\u端口中:
尝试:
使用contextlib.closing(socket.socket(*socket\u args,**socket\u kwargs))作为我的套接字:
my_socket.bind((绑定地址,最低端口))
此端口=我的套接字。getsockname()[1]
保留的\u端口。添加(此\u端口)
返回此端口
除了socket.error作为错误:
如果不是error.errno==errno.eaddrin,请使用:
提升
断言不是最低的\u端口==0
保留的\u端口。添加(最低的\u端口)
最低_端口+=1
引发异常('找不到打开的端口')

临时端口基本上位于49152-65535之间。 如果您想在更大范围内检查端口,只需更改randint中的值

import pustil
from random import randint
def getfreeport():
    port = randint(49152,65535)
    portsinuse=[]
    while True:
        conns = pstuil.net_connections()
        for conn in conns:
            portsinuse.append(con.laddr[1])
        if port in portsinuse:
            port = randint(49152,65535)
        else:
            break
    return port

通过将套接字绑定到操作系统选择的端口,可以找到空闲端口。操作系统选择端口后,可以释放套接字。但是,此解决方案不抵抗竞争条件-在获得空闲端口号和使用此端口之间的短时间内,其他进程可能会使用此端口

def find_free_port():
    s = socket.socket()
    s.bind(('', 0))            # Bind to a free port provided by the host.
    return s.getsockname()[1]  # Return the port number assigned.

这就像狗追逐汽车-当你得到一辆车时,你会怎么做?我需要另一个控制台应用程序的TCP端口号,它需要一个端口作为它将侦听的参数。对于你正在考虑的方法,存在一个明显的(尽管很小)竞争条件。当您将端口传递给另一个进程时,该端口可能已被占用。您是否拥有另一个进程的代码?如果是这样,最好让它获取一个随机端口,并将其报告给第一个进程。是的,这正是我所说的“不是100%正确”的意思。但是,在我获取端口和调用另一个进程之间,总会有这么短的时间间隔。(我没有这个代码。)为什么要使用listen()调用?对我来说,只要我调用bind(),就填充了s.getsockname()[1],在
s.close()
之前调用
s.shutdown()
在这种情况下?fwiw,这与流行的节点包
get port
使用的方法相同。不幸的是,这不是100%的故障防护,当端口确实被另一个应用程序使用时,可能会返回True。我还没有弄清楚原因,但是当另一个进程已经在侦听端口时,.bind()不会总是失败。@Joe是否可能另一个应用程序绑定到不同的地址,但具有相同的端口?或者不同的家庭住址?这是可能的。我所知道的是,在我的例子中,我试图启动的服务器应用程序未能打开该端口,尽管上面的代码说该端口是免费的。另一个应用程序是erl.exe(erlang),如果您想自己尝试的话,我通过RabbitMQ的设置获得了它