【问题标题】:Reserve a TCP port in Windows在 Windows 中保留 TCP 端口
【发布时间】:2011-07-12 09:04:51
【问题描述】:

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

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

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

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

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

背景

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

【问题讨论】:

  • 请注意,Windows 确实支持大致相当于 Unix 套接字的东西,它被称为“命名管道”(流和消息/数据报模式都可用)。所以最好的解决方案可能是在 Win32 上实现“ipc:”。
  • @BenVoigt 感谢您的建议。不幸的是,命名管道的语义与套接字有很大的不同,以至于大多数应用程序不能将它们用作直接替代品。

标签: windows network-programming zeromq


【解决方案1】:

正如@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 版或第 6 版保留端口,但不能同时为两者保留(即不能为 TCPv4 和 TCPv6 保留端口 60000)

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • +1 以获得好建议。这让我意识到,甚至不需要更改设置,只需查询动态端口范围并选择超出范围的端口号即可。但是,我重新考虑(并编辑)了我的问题,以更准确地反映我所追求的目标,而了解或操纵动态端口范围并没有真正帮助。
    【解决方案3】:

    编辑:这仅适用于 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

    【讨论】:

    • 感谢您花时间回答,但我不想摆弄注册表。
    • 这适用于 Server 2003,但在 Server 2008 以后,ReservedPorts 注册表设置为 removed
    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-19
        • 2011-09-05
        • 2011-01-17
        • 2011-08-14
        • 1970-01-01
        • 1970-01-01
        • 2016-06-06
        相关资源
        最近更新 更多