3

2 つのサーバー ソケットを作成select()し、それらを呼び出して新しい接続を待機する親プロセスがあります。接続が到着すると、メッセージが子プロセスに送信されます (fork()サーバー ソケットの作成後に で作成されるため、共有されます)。

この子でaccept()は、サーバー ソケットでの呼び出しは機能しません。エラーが発生しましたEAGAIN(ノンブロッキング ソケット)。一方、メイン プロセスの呼び出しaccept()は完全に機能します。

もちろん、私はaccept()メイン プロセスをまったく呼び出しません。動作するかどうかをテストしただけで、動作します。

accept()プロセスの後に子プロセスを呼び出せないのはなぜですか?select()

編集: ここでの目標は、prefork モデルのように、クライアント接続を処理するために一定数のワーカー (8 としましょう) を作成することです。これらの接続は、HTTP とは異なり、長時間の接続になります。目標は、ワーカー間の接続の負荷を分散することです。

これを行うには、現在接続されているクライアントの数をワーカーに格納する共有メモリ変数を使用します。クライアント数が最も少ないワーカーに、新しい接続を処理するよう「依頼」したいと考えています。

そのselect()ため、新しい接続を処理するプロセスを「選択」したいので、親で を実行してから子プロセスにメッセージを送信します。

サーバーは複数のソケット (ssl 用に 1 つ、ssl 用に 1 つ、なし) でリッスンします。これが、子プロセスでselect()直接ではなく使用する理由です。これは、子ワーカーで複数のソケットを使用できないためです。accept()accept()

4

1 に答える 1

4

実際、問題は私が最初に考えたものではありませんでした。これは、ワーカー プロセス間の接続の基本的な負荷分散を実現するために行ったことの要約です。

  • メイン プロセス (親) が 2 つのサーバー ソケットを作成し、それらを bind() および listen() します (たとえば、ssl を使用する場合と使用しない場合)。
  • fork() で 8 つの子プロセスを作成するので、それらは親のソケットを継承します。
  • メインプロセスはselect()無限ループで実行されます
  • 2 つのソケットのいずれかが使用可能になると、パイプを介して子にメッセージを送信します。子は、「子プロセス内」のクライアントの現在の数を含む共有メモリ値のおかげで決定されます。現在処理するクライアント数が最も少ないプロセスが選択されます。
  • 次に、この子プロセスaccept()はサーバー ソケットを呼び出します (2 つの間で使用されるソケットはパイプで渡されるため、子プロセスはどちらを呼び出すかを認識しますaccept())。

問題は、私の親プロセスが子にソケットを受け入れ、その直後にループに再び入るように指示し、ループがselect()再び実行されることでした。ただし、子がまだソケットを受け入れていない場合はselect()、同じ接続に対して再び戻ります。そのため、EAGAIN エラーが発生しました。実際、2 回呼び出しました (速度accept()によってはそれ以上—プロセス間競合状態)!

解決策は、子供がパイプで「ねえ、接続を受け入れました。大丈夫です!」などの応答を待ってから、select()ループに戻ることです。

これは完全に正常に機能します。Python での実装は、好奇心旺盛な方のためにこちらから入手できます: https://github.com/thhibautd/Kiwi !

于 2012-04-13T23:27:55.550 に答える