33

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

4

5 回答 5

68

我目前的解决方案:

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% 正确,但它现在有效。

于 2010-05-14T23:48:12.003 回答
18

可以通过将套接字绑定到操作系统选择的端口来找到空闲端口。操作系统选择一个端口后,就可以对socket进行处理了。然而,这个解决方案不能抵抗竞争条件——在获得空闲端口号和使用这个端口之间的很短的时间内,其他进程可能会使用这个端口。

import socket

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

https://godbolt.org/z/fs13K13dG

于 2016-03-31T11:16:02.993 回答
3

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

port = random.randint(10000,60000)

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

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

于 2010-05-15T00:12:29.537 回答
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
于 2015-09-09T06:42:00.210 回答
0

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

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')
于 2014-02-28T21:55:59.927 回答