後でサービスによってバインドされるようにTCPポートを予約したいので、Windowsがランダムなポート番号を割り当てるときに誤って同じ番号を使用することはありません。これはレジストリと再起動ですが、私はそのような手間のかかる解決策を避けたいと思います。
プロセスが実際にポートをバインド/リッスンせずにポートを予約し、要求に応じて安全に(つまり、競合状態を回避して)別のプロセスにポートを渡すにはどうすればよいですか?
ポート番号を事前に決定する必要はありません。最初のプロセスがランダムなポート番号を取得し、それを要求側のプロセスに渡しても問題ありません。
編集:私の質問はやや不十分に述べられていることに気づきました。私が本当に望んでいるのは、動的ポート番号の割り当てをポートゼロへのバインド操作から分離することです。これは、そのポート番号の偶発的なランダム割り当てを回避するだけでなく、他のプロセスが暫定的に同じアドレス/ポートにバインドするのを防ぐことも意味します。または、別の言い方をすれば、1つのプロセスでポートゼロへのバインド操作を開始し、使用されるポート番号をすぐに学習して、指定された2番目のプロセスに将来のバインド操作を完了させたいと考えています。
現時点で考えられる最も近い回避策は、最初のプロセスがすぐにアドレス/ 0にバインドし、2番目のプロセスがそれを要求するまでバインドされたままで、その時点でバインドを解除して、他のプロセスにポート番号を通知することです。取得され、アドレス/ポートに明示的にバインドされます。これには2つの問題があります。1)2番目のプロセスが実行されるまで、バインドしたくない。 2)サードパーティが誤って(または故意に)ポートを奪う可能性がある短い時間間隔があります。
なぜ私がそんなに奇妙なことをしたいのか不思議に思うかもしれません。私はZeroMQをいじっていますが、大きな制限の1つは、Windowsにipc://
トランスポートがないことです。ポートマッパープロセス(RPCエンドポイントマッパーまたはErlangのepmdに似ています)は、動的なポート割り当てでtcp://
トランスポートを使用して回避策を実装するための単なるチケットであることに気づきました。ただし、ZeroMQクライアントとサーバーは順不同で接続できます(つまり、サーバーがバインドする前にクライアントが接続するのはエラーではありません)。そのため、接続しているクライアントがどのように検出できるかを理解しようとしています。高度な確実性—サーバーが実際にそのポートにバインドする前に通信に使用されるポート。
@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 を参照してください。
netshコマンドを使用すると役立つ場合があります。 Windowsで使用される動的ポート範囲を変更できます。
指定したレジストリの変更と似ていますが、すぐに有効になります。
netshコマンドの詳細については、 http://support.Microsoft.com/kb/929851 を参照してください。
編集:これは、Windows Server 2008より前のバージョンにのみ適用されます( MicrosoftサポートKB )
'ReservedPorts'レジストリ設定はで編集できます
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
ポートの範囲を予約するには、「4000-4010」または「xxxx-yyyy」の形式に従いますが、単一のポートを予約するには、「4000-4000」または「xxxx-xxxx」の形式を使用する必要があります。
私は可能な解決策を考え出したので、答えとしてここにそれを文書化したほうがよいと思いました。
プロセスは、WSADuplicateSocketの呼び出しを介してソケットを別のプロセスに渡すことができるため、調整プロセスは動的ポートにバインドし、それを指定されたIPC名前。ZMQサーバーの場合その名前に「バインド」したいプロセスが到着すると、調整プロセスはバインドされたソケットをサーバープロセスにコピーし、自身のコピーを閉じます。
このソリューションは、bind()の呼び出しを回避するという私の好みに対応していませんが、厳密には必要ない場合があります。いくつかのテストを実行する必要があります。
ZeromMQの場合、czmqまたはC#NetMqのzbeacon
モジュールを使用して、サービス検出を実装できます。