在localhost上,如何选择空闲端口号?


161

我正在尝试进行进程间通信,并且由于无法弄清楚如何在Windows下使用命名管道,因此我认为我将使用网络套接字。一切都发生在本地。服务器能够在单独的进程中启动从属服务器,并在某些端口上进行侦听。奴隶完成工作并将结果提交给主人。如何确定哪个端口可用?我假设我无法在端口80或21上收听?

我正在使用Python,如果这样做会减少选择的余地。

谢谢!


1
顺便说一句,如果您只是选择一个随机的或随机ish的端口号(最好大于1024),则该端口号可能会可用。您甚至可以使用端口80或21或任何其他端口,只要没有其他程序正在监听它即可。在任何给定时间,在正常系统上,只有一小部分端口在使用中。
David Z

19
选择一个随机端口不是一个好主意-让操作系统为您选择一个端口。
Corehpf

Answers:


225

不要绑定到特定端口,也不要绑定到端口0,例如sock.bind(('', 0))。然后,操作系统将为您选择一个可用端口。您可以使用来获得选择的端口sock.getsockname()[1],并将其传递给从站,以便它们可以重新连接。


4
有关sock.bind(('',0))
cevaris

10
您如何将号码传递给奴隶?对我来说听起来像是鸡和鸡蛋的问题。
塞巴斯蒂安

2
如果从属是在绑定后创建的,则可以在创建它们时将其作为参数传递。或者,您可以将其写入共享内存或都可以访问的文件中,或者通过某个众所周知的端口号访问的中央服务器可以对其进行跟踪。
mark4o

49

为了简要说明上面的解释:

import socket
from contextlib import closing

def find_free_port():
    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
        s.bind(('', 0))
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        return s.getsockname()[1]

3
如果在本地主机上:也许s.bind(('localhost', 0))更好
codeskyblue

3
添加以下内容也很好,因此您可以在返回语句之前快速重用该端口:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird

1
@jonEbird socket.SO_REUSEADDR在这种情况下真的有帮助吗?据我了解,尝试绑定的套接字具有唯一的意义,SO_REUSEADDR与是否在持久套接字上设置该标志无关紧要。
卡尔·巴特尔

41

将套接字绑定到端口0。将选择一个从1024到65535的随机空闲端口。您可以在getsockname()之后紧跟着检索选定的端口bind()


2

您可以在任何端口上侦听;通常,用户应用程序应侦听端口1024及更高端口(通过65535)。如果您的侦听器数量可变,那么最主要的事情就是为您的应用分配一个范围-例如20000-21000和CATCH EXCEPTIONS。这样,您将知道计算机上端口是否不可用(换句话说,由另一个进程使用)。

但是,就您而言,只要绑定失败时打印错误消息,就可以为侦听器使用单个硬编码端口,这不会有问题。

还要注意,您的大多数套接字(用于从属)不需要显式绑定到特定的端口号-仅需要将等待传入连接的套接字(例如此处的主机)设置为侦听器并绑定到端口。如果在使用套接字之前未为端口指定端口,则操作系统将为该套接字分配可用端口。当主机希望响应从机发送数据时,当侦听器接收数据时,可以访问发送者的地址。

我想您将为此使用UDP?


0

如果您只需要找到一个空闲端口供以后使用,这是一个类似于先前答案的代码段,但使用socketserver则更短:

import socketserver

with socketserver.TCPServer(("localhost", 0), None) as s:
    free_port = s.server_address[1]

请注意,不能保证端口保持空闲状态,因此您可能需要将此代码段和使用它的代码放入循环中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.