Зарезервировать порт TCP в Windows
Я хотел бы зарезервировать TCP-порт, который позже будет связан службой, так что Windows не будет непреднамеренно использовать один и тот же номер при назначении случайных номеров портов. Я знаю, что это возможно через реестр и перезагрузка, но я бы хотел избежать такого жесткого решения.
Как процесс может зарезервировать порт без фактического привязки/прослушивания, а затем безопасно (т.е. избегая условий гонки) передать его другому процессу по запросу?
Номер порта не обязательно должен быть определен заранее. Это нормально, чтобы первый процесс приобрел случайный номер порта и передал его процессу запроса.
EDIT: Мне кажется, что мой вопрос несколько плохо сформулирован. Я действительно хочу отделить выделение номера динамического порта от операции привязки к порту-ноль. Это означает, что вы не просто избегаете случайного случайного распределения этого номера порта, но также предотвращаете привязку любого другого процесса к одному и тому же адресу/порту в промежуточный период. Или, говоря другим способом, я хочу, чтобы один процесс запустил операцию привязки к порту-ноль - сразу же узнав номер порта, который будет использоваться, и пусть назначенный второй процесс завершит операцию привязки в будущем.
В настоящий момент самое близкое взаимодействие, о котором я могу думать, заключается в том, что первый процесс сразу связывается с адресом /0 и остается связанным до тех пор, пока второй процесс не запросит его, и в этот момент он отсоединяет и сообщает другому процессу номер порта, который он приобрел, который затем привязывается к адресу/порту явно. У этого есть две проблемы: 1) я бы предпочел не связываться вообще до тех пор, пока не будет второй процесс; 2) существует небольшой промежуток времени, в течение которого третья сторона может случайно (или намеренно) узурпировать порт.
Фон
Вам может быть интересно узнать, почему я хочу сделать что-то такое странное. Я работал с ZeroMQ, и одним из основных ограничений является отсутствие транспорта ipc://
в Windows. Мне показалось, что процесс сопоставления портов (аналогичный RPC endpoint mapper или Erlang epmd) будет всего лишь билетом для реализации обхода с использованием транспорта tcp://
с динамическими распределениями портов. Тем не менее, клиентам и серверам ZeroMQ разрешено подключаться не по порядку (т.е. Это не ошибка для подключения клиента до привязки сервера), поэтому я пытаюсь выяснить, как можно обнаружить подключающийся клиент - с очень высокая степень достоверности - порт, который будет использоваться для связи, до того, как сервер действительно свяжется с этим портом.
Ответы
Ответ 1
Использование команды netsh может помочь вам. Вы можете изменить диапазон динамического порта, используемый Windows.
Это похоже на изменение реестра, которое вы указали, но оно действует немедленно.
см. http://support.microsoft.com/kb/929851 для получения дополнительной информации о команде netsh.
Ответ 2
Как упоминалось в @vahapt, вы можете изменить диапазон динамических портов с помощью netsh
.
Однако лучшим решением может быть использование netsh для резервирования портов, требуемых вашим приложением, оставив по умолчанию диапазон динамических портов по умолчанию.
Для этого:
- На сервере 2008/2008 R2 установите это исправление Microsoft. Это не требуется на сервере 2012 года или позже.
-
Остановить любые процессы, используя зарезервированные порты. Если процесс использует порт, включенный в диапазон портов для резервирования, NETSH вернет следующую ошибку, и резервирование не будет выполнено:
Процесс не может получить доступ к файлу, потому что он используется другим процессом.
-
Используйте следующую команду NETSH для резервирования портов:
netsh int <ipv4|ipv6> Add excludedportrange [protocol=]tcp|udp [startport=]<integer> [numberofports=]<integer> [[store=]active|persistent]
Например, чтобы зарезервировать порты 55368-55372 для UDPv6, используйте команду:
netsh int ipv6 add excludedportrange protocol=udp startport=55368 numberofports=5
Примечания:
- По умолчанию резервирование портов сохраняется при перезагрузках
- Порты могут быть зарезервированы для версий 4 или 6 протокола, но не для обоих (т.е. вы не можете зарезервировать порт 60000 для TCPv4 и TCPv6)
Для получения дополнительной информации см. https://support.microsoft.com/en-us/kb/929851, в том числе о том, как просматривать или удалять существующие резервирования портов.
Ответ 3
Изменить: это относится только к pre-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
Ответ 4
Я придумал возможное решение, поэтому я подумал, что могу записать его здесь как ответ.
Процесс может передать сокет другому процессу посредством вызова WSADuplicateSocket, поэтому процесс координации может связываться с динамическим портом и внутренне связывать его с данным именем IPC. Когда приходит процесс сервера ZMQ, который хочет "привязать" к этому имени, координирующий процесс копирует связанный сокет в серверный процесс и закрывает его собственную копию.
Это решение не относится к моим предпочтениям, чтобы избежать вызова bind(), но это может быть не обязательно; Мне нужно будет выполнить некоторые тесты.
Ответ 5
Для ZeromMQ вы можете использовать модуль zbeacon
czmq или С# NetMq для реализации обнаружения службы.