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