我想在 Python 中的 localhost 上获取任何随机打开的 TCP 端口。最简单的方法是什么?
5 回答
我目前的解决方案:
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% 正确,但它现在有效。
可以通过将套接字绑定到操作系统选择的端口来找到空闲端口。操作系统选择一个端口后,就可以对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.
我实际上在我的一个程序中使用了以下内容:
port = random.randint(10000,60000)
当然,这比您拥有的代码更容易发生冲突。但我从来没有遇到过问题。关键是,在任何给定时间,这些高编号端口中的大多数都未使用,如果您只是随机选择一个,那么与另一个进程发生冲突的可能性很小。如果您执行类似于您在答案中发布的解决方案(打开套接字并获取其端口号),则几乎可以肯定该端口不会发生冲突。因此,如果这只是您自己使用的东西(而不是您要向公众发布的东西),请考虑是否值得提出一个真正的防弹解决方案。很可能它永远不会有所作为。
受 Marcelo Cantos 对您的问题的评论的启发,我将补充说,在这种情况下,标准解决方案是将使用端口的进程绑定到它,然后与需要它的任何其他程序共享该信息。通常它会做一些事情,比如将包含端口号的临时文件写入文件系统中的某个标准位置。由于您正在使用的过程不会这样做,因此从某种意义上说,您提出的任何解决方案都会有点麻烦。但同样,如果它只是供您自己使用,那可能没问题。
临时端口基本上位于 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
这是我的版本,但是如果您指定端口范围,它并不是真正随机的。这也会受到竞争条件的影响,但如果您需要提前了解端口,这是我知道的最好方法。
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')