1. ホーム
  2. sockets

[解決済み] 複数のプロセスで1つのリスニングソケットを共有する方法はありますか?

2023-01-20 20:50:19

質問

ソケットプログラミングでは、リスニングソケットを作成し、クライアントが接続するたびに、クライアントのリクエストを処理するために使用する通常のストリームソケットを取得します。OSは、着信接続のキューを舞台裏で管理します。

2つのプロセスが同時に同じポートにバインドすることはできません - とにかく、デフォルトでは。

(よく知られた OS、特に Windows で) プロセスの複数のインスタンスを起動し、それらがすべてソケットにバインドされ、キューを効果的に共有するような方法があるかどうか疑問に思っています。各プロセスインスタンスはシングルスレッドで、新しい接続を受け入れるときだけブロックすることができます。クライアントが接続すると、アイドル状態のプロセス インスタンスの 1 つがそのクライアントを受け入れることになります。

これにより、各プロセスは非常にシンプルなシングルスレッド実装となり、明示的な共有メモリを使用しない限り何も共有せず、ユーザーはさらにインスタンスを起動することにより処理帯域幅を調整できるようになります。

そのような機能は存在するのでしょうか?

編集してください。 なぜスレッドを使わないのか」という質問に対して、スレッドは選択肢の一つであることは明らかです。しかし、1 つのプロセスで複数のスレッドを使用すると、すべてのオブジェクトが共有可能になり、オブジェクトが共有されないか、一度に 1 つのスレッドにしか見えないか、絶対に不変であることを保証するために細心の注意を払わなければなりませんが、人気のある言語とランタイムのほとんどは、この複雑さを管理するための組み込みサポートを欠いています。

一握りの同一のワーカープロセスを起動することで、同時実行システムを得ることができ、その中で デフォルト は共有されず、正しくスケーラブルな実装を構築することがより簡単になります。

どのように解決するのですか?

LinuxやWindowsでも、2つ(またはそれ以上)のプロセス間でソケットを共有することができます。

Linux (またはPOSIX系OS) では fork() を使うと、フォークされた子は親のファイルディスクリプタのコピーを全て持つようになります。クローズされないものは共有され続け、(例えば TCP リスニングソケットで) accept() に使用することができます。これは、ほとんどの場合、Apache を含む多くのサーバーが動作する方法です。

Windows では、基本的に同じことが言えます。 fork() システムコールがないので、親プロセスは CreateProcess などを使用して子プロセスを作成し (もちろん同じ実行ファイルを使用することができます)、継承可能なハンドルを渡す必要があります。

リッスンするソケットを継承可能なハンドルにすることは、完全に些細な活動ではありませんが、それほど厄介なことでもありません。 DuplicateHandle() を使用して複製ハンドルを作成する必要があります (ただし、まだ親プロセスにあります)。この複製ハンドルには継承可能フラグが設定されています。そして、そのハンドルに STARTUPINFO 構造で、CreateProcess で子プロセスに STDIN , OUT または ERR というハンドルがあります (他のことに使いたくなかったと仮定して)。

EDITです。

MDSN ライブラリを読むと、どうやら WSADuplicateSocket は、これを行うより堅牢で正しいメカニズムです。親プロセスと子プロセスは、何らかのIPCメカニズムによって複製される必要があるハンドルを見つけ出す必要があるので、これはまだ非自明です(これはファイルシステム内のファイルのように単純である可能性もありますが)。

明確化。

OP の最初の質問に対する答えとして、いいえ、複数のプロセスでは bind() 元の親プロセスだけが bind() , listen() などで、子プロセスは単に accept() , send() , recv() など。