17

我想保留一个 TCP 端口,以便稍后由服务绑定,以便 Windows 在分配随机端口号时不会无意中使用相同的数字。我知道这可以通过注册表和重新启动来实现,但我想避免这种笨拙的解决方案。

一个进程如何在没有实际绑定/监听的情况下保留一个端口,然后根据请求安全地(即避免竞争条件)将其移交给另一个进程?

端口号不需要预先确定。第一个进程可以获取一个随机端口号,并将其传递给请求进程。

编辑:在我看来,我的问题表述得有些不好。我真正想要的是将动态端口号的分配与绑定到端口零操作分开。这意味着不仅要避免意外随机分配该端口号,还要防止任何其他进程在此期间绑定到同一地址/端口。或者,换一种说法,我希望一个进程启动绑定到端口零的操作——立即了解将使用的端口号——并让指定的第二个进程在未来某个时间完成绑定操作。

目前,我能想到的最接近的解决方法是让第一个进程立即绑定到 address/0,并保持绑定直到第二个进程请求它,此时它解除绑定并告诉另一个进程它的端口号获取,然后显式绑定到地址/端口。这有两个问题:1)我宁愿在第二个过程出现之前根本不绑定;2)有一小段时间间隔,在此期间第三方可能会意外(或故意)篡夺端口。

背景

你可能会好奇我为什么要做这么奇怪的事情。我一直在玩弄 ZeroMQ,一个主要的限制是ipc://Windows 上没有传输。让我感到震惊的是,端口映射器进程(类似于 RPC 端点映射器,或 Erlang 的 epmd)只是使用tcp://具有动态端口分配的传输实现解决方法的门票。但是,ZeroMQ 客户端和服务器允许无序连接(即,客户端在服务器绑定之前连接不是错误),所以我试图弄清楚连接客户端如何发现 - 非常高度确定性——在服务器实际绑定到该端口之前,将用于通信的端口。

4

5 回答 5

7

正如@vahapt 所述,您可以使用netsh.

但是,更好的解决方案可能是使用 netsh 来保留应用程序所需的端口,而不管动态端口的默认范围。

为此:

  1. 在 Server 2008/2008 R2 上,安装此Microsoft 修补程序。这在 Server 2012 或更高版本上不是必需的。
  2. 停止使用要保留的端口的任何进程。如果进程正在使用包含在要保留的端口范围内的端口,NETSH 将返回以下错误并且保留将失败:

    该进程无法访问该文件,因为它正被另一个进程使用。

  3. 使用以下 NETSH 命令保留端口:

    netsh int <ipv4|ipv6> Add excludedportrange [protocol=]tcp|udp [startport=]<integer> [numberofports=]<integer> [[store=]active|persistent]

    例如,要为 UDPv6 保留端口 55368-55372,请使用以下命令:

    netsh int ipv6 add excludedportrange protocol=udp startport=55368 numberofports=5

笔记:

  • 默认情况下,端口保留在重新启动后保持不变
  • 端口可以​​为协议的第 4 版或第 6 版保留,但不能同时为两者保留(即您不能为 TCPv4 和 TCPv6 保留端口 60000)

有关更多信息,包括如何查看或删除现有端口预留,请参阅https://support.microsoft.com/en-us/kb/929851 。

于 2016-06-06T16:07:44.727 回答
6

使用netsh命令可能会对您有所帮助。您可以更改 Windows 使用的动态端口范围。
就像你指出的注册表修改,但它是立即生效的。

有关 netsh 命令的详细信息,请参见: http: //support.microsoft.com/kb/929851

于 2011-03-10T01:27:21.370 回答
5

编辑:这仅适用于 Windows Server 2008 之前的版本(Microsoft Support KB

您可以在中编辑“ReservedPorts”注册表设置

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

要保留一系列端口,请遵循“4000-4010”或“xxxx-yyyy”格式,但要保留单个端口,您必须使用“4000-4000”或“xxxx-xxxx”格式

http://support.microsoft.com/kb/812873

于 2012-02-01T21:51:37.820 回答
2

我想出了一个可能的解决方案,所以我想我不妨把它记录在这里作为答案。

进程可以通过调用 WSADuplicateSocket 将套接字传递给另一个进程,因此协调进程可以绑定到动态端口,并在内部将其与给定的 IPC 名称相关联。当想要“绑定”到该名称的 ZMQ 服务器进程到达时,协调进程将绑定的套接字复制到服务器进程并关闭它自己的副本。

这个解决方案没有解决我避免调用 bind() 的偏好,但这可能不是绝对必要的;我将不得不进行一些测试。

于 2011-03-15T01:37:27.247 回答
0

For ZeromMQ, you can use the zbeacon module from czmq or C# NetMq to implement service discovery.

于 2015-03-13T14:25:04.107 回答