我想保留一个TCP端口,稍后再被一个服务绑定,以便Windows在分配随机端口号时不会无意中使用相同的号码。 我知道这是可能的通过registry和重新启动,但我想避免这样一个严重的解决scheme。
一个进程如何在不实际绑定/监听的情况下保留一个端口,然后安全地(即避免竞态条件)根据请求将其交给另一个进程?
端口号不需要事先确定。 第一个进程可以获得一个随机的端口号,并将其传递给请求进程。
编辑:它发生在我身上,我的问题是有点陈述。 我真正想要的是将dynamic端口号的分配从bind-to-port-zero操作中分离出来。 这意味着不仅要避免意外的随机分配该端口号,而且还要防止在此期间任何其他进程绑定到相同的地址/端口。 换句话说,我想让一个进程启动bind-to-port-zero操作 – 立即学习将被使用的端口号 – 并让指定的第二个进程在将来完成绑定操作。
目前,我能想到的最接近的解决方法是,第一个进程立即绑定到地址/ 0,并保持绑定,直到第二个进程请求它,此时解除绑定并告知其他进程的端口号获得,然后明确绑定到地址/端口。 这有两个问题:1)我宁愿不要束缚,直到第二个过程出现。 2)第三方可能意外(或故意)篡夺港口的时间间隔很短。
你可能会好奇我为什么要做这么奇怪的事情。 我一直在玩ZeroMQ,一个主要的限制是没有Windows上的ipc://
传输。 令我感到震惊的是,端口映射器进程(类似于RPC端点映射器,或者Erlang的epmd)只是使用具有dynamic端口分配的tcp://
transport来实现解决scheme的票据。 然而,ZeroMQ客户端和服务器被允许连接不顺序(即在服务器绑定之前,客户端连接不是错误的),所以我试图找出连接客户端如何发现 – 一个非常高度确定性 – 在服务器实际绑定到端口之前将用于通信的端口。
使用netsh命令可能会帮助你。 您可以更改Windows使用的动态端口范围。
它就像您指出的注册表修改,但立即生效。
请参阅: http : //support.microsoft.com/kb/929851有关netsh命令的详细信息。
如@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 ,其中包括如何查看或删除现有端口预留。
编辑:这只适用于Windows server 2008之前( Microsoft支持KB )
你可以编辑'ReservedPorts'注册表设置
HKEY_LOCAL_MACHINE \系统\ CurrentControlSet \服务\ TCPIP \参数
要保留一个范围的端口,请按照格式“4000-4010”或“xxxx-yyyy”进行,但要保留一个端口,必须使用“4000-4000”或“xxxx-xxxx”
我想出了一个可能的解决方案,所以我想我也可以在这里把它作为一个答案。
进程可以通过调用WSADuplicateSocket将套接字传递给另一个进程,因此协调进程可以绑定到动态端口,并在内部将其与给定的IPC名称相关联。 当需要“绑定”到该名称的ZMQ服务器进程到达时,协调进程将绑定的套接字复制到服务器进程并关闭自己的副本。
这个解决方案没有解决我的偏好,以避免调用bind(),但这可能不是绝对必要的; 我将不得不执行一些测试。
对于ZeromMQ,您可以使用czmq或C#NetMq中的zbeacon
模块来实现服务发现。