在Windows中保留TCP端口

时间:2011-03-10 01:09:12

标签: windows network-programming zeromq

我想保留一个TCP端口,稍后再被服务绑定,这样Windows在分配随机端口号时不会无意中使用相同的号码。我知道这可以通过注册表和重新启动,但我想避免这种严厉的解决方案。

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

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

编辑:我觉得我的问题有点陈述。我真正想要的是将动态端口号的分配与bind-to-port-zero操作分开。这意味着不仅要避免意外随机分配该端口号,还要防止任何其他进程在此期间绑定到同一地址/端口。或者,换句话说,我希望一个进程启动bind-to-port-zero操作 - 立即学习将要使用的端口号 - 并让指定的第二个进程在将来的某个时间完成绑定操作。

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

背景

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

5 个答案:

答案 0 :(得分:6)

如@vahapt所述,您可以使用netsh修改动态端口范围。

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

这样做:

  1. 在Server 2008/2008 R2上,安装此Microsoft hotfix。 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. 备注:

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

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

答案 1 :(得分:5)

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

请参阅:http://support.microsoft.com/kb/929851了解有关netsh命令的详细信息。

答案 2 :(得分:4)

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

您可以在

中编辑'ReservedPorts'注册表设置

HKEY_LOCAL_MACHINE \ SYSTEM \ CURRENTCONTROLSET \服务\ TCPIP \参数

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

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

答案 3 :(得分:2)

我想出了一个可能的解决方案,所以我想我也可以在这里将其作为答案进行记录。

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

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

答案 4 :(得分:0)

对于ZeromMQ,您可以使用czmq或C#NetMq中的zbeacon模块来实现服务发现。