我想保留一个TCP端口,稍后再被服务绑定,这样Windows在分配随机端口号时不会无意中使用相同的号码。我知道这可以通过注册表和重新启动,但我想避免这种严厉的解决方案。
一个进程如何在没有实际绑定/侦听它的情况下保留一个端口,然后安全地(即避免竞争条件)根据请求将其移交给另一个进程?
无需事先确定端口号。第一个进程可以获取随机端口号,并将其传递给请求进程。
编辑:我觉得我的问题有点陈述。我真正想要的是将动态端口号的分配与bind-to-port-zero操作分开。这意味着不仅要避免意外随机分配该端口号,还要防止任何其他进程在此期间绑定到同一地址/端口。或者,换句话说,我希望一个进程启动bind-to-port-zero操作 - 立即学习将要使用的端口号 - 并让指定的第二个进程在将来的某个时间完成绑定操作。
目前,我能想到的最接近的解决方法是第一个进程立即绑定到地址/ 0,并保持绑定直到第二个进程请求它,此时它解除绑定并告诉另一个进程它获取的端口号,然后显式绑定到地址/端口。这有两个问题:1)在第二个过程出现之前我根本不会绑定; 2)有一小段时间间隔,第三方可能会意外(或故意)篡夺该端口。
你可能很好奇为什么我想做一些如此奇怪的事情。我一直在玩ZeroMQ,一个主要的限制是Windows上没有ipc://
传输。让我感到震惊的是,端口映射器进程(类似于RPC终结点映射器,或Erlang的epmd)只是使用带有动态端口分配的tcp://
传输来实现解决方案的工具。但是,允许ZeroMQ客户端和服务器无序连接(即,在服务器绑定之前,客户端连接不是错误),所以我试图弄清楚连接客户端如何发现 - 非常高度确定性 - 在服务器实际绑定到该端口之前用于通信的端口。
答案 0 :(得分:6)
如@vahapt所述,您可以使用netsh
修改动态端口范围。
但是,更好的解决方案可能是使用netsh来保留应用程序所需的端口,而不管是默认的动态端口范围。
这样做:
使用要保留的端口停止任何进程。如果进程正在使用要保留的端口范围中包含的端口,则NETSH将返回以下错误,并且预留将失败:
该进程无法访问该文件,因为该文件正由另一个进程使用。
使用以下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
备注:强>
有关详细信息,请参阅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”格式
答案 3 :(得分:2)
我想出了一个可能的解决方案,所以我想我也可以在这里将其作为答案进行记录。
进程可以通过调用WSADuplicateSocket将套接字传递给另一个进程,因此协调进程可以绑定到动态端口,并在内部将其与给定的IPC名称相关联。当想要“绑定”到该名称的ZMQ服务器进程到达时,协调进程将绑定的套接字复制到服务器进程并关闭其自己的副本。
这个解决方案没有解决我避免调用bind()的偏好,但这可能不是绝对必要的;我将不得不进行一些测试。
答案 4 :(得分:0)
对于ZeromMQ,您可以使用czmq或C#NetMq中的zbeacon
模块来实现服务发现。