4

非同期 I/O でネットワーク クライアントを処理するサーバー アプリケーションがあります。クライアント接続は受け入れられ、poll/epoll/select/etc で監視できる記述子セットに追加されます。apr_pollset_poll() apache APR ライブラリ呼び出しを使用して、読み取りまたは書き込みが可能な記述子をチェックしています。これは、プラットフォームに応じて内部的に epoll/poll/select/etc を使用します。

問題は、何らかの形でソケット記述子の 1 つが破損し、apr_pollset_poll が WSAENOTSOCK である errno 10038 を返すことです: ソケットではないものに対して操作が試行されました。残念ながら、これにより、特定のクライアント接続を開始するだけでなく、アプリケーションがまったく動作しなくなります。このソケットを記述子セットから無視または削除できれば、引き続き機能し、他のソケットを適切に読み書きできます。ソケットが破損する根本的な原因を見つけなければならないことはわかっていますが、フェイルセーフな回避策が必要です。

記述子がポーリングセットに追加されると、これらは OS/カーネルによって処理され、反復できるようにそれらを取得する方法がわかりません。これらを自分のリストでも維持すると、おそらくさらに下に他の問題が発生する可能性があります。これは、ソケットを閉じるときに、カーネル内のポーリングセットに対して自動的に発生する何らかの方法でそれらをクリーンアップする必要があるためです。

助言がありますか?

4

2 に答える 2

2

悲惨なように聞こえますが、発生した場合は緊急事態です。したがって、作業中のポーリングセット内のすべての記述子を調べて、記述子が偽物である場合にそのエラーをトリガーする操作をその記述子に対して実行することをお勧めします。たとえば、新しい一時的なポーリング セットを作成し、ノンブロッキング ゼロ タイムアウト ポーリング操作を試行して、エラーが発生するかどうかを確認できます。

たとえば、投票セットに 12 個以上の記述子がある場合は、1 つずつアプローチする代わりに、バイナリ検索を検討することもできます。記述子の半分を一時ポーリングセットに入れてから、操作を実行できます。失敗した場合は、試したセットに偽の記述子があることがわかります。2つに分けて、もう一度やり直してください。失敗しない場合は、偽の記述子が他のセットにあると推定できます。残りの半分が失敗することを検証するか、失敗すると仮定して残りを 2 つに分割して再試行できます。失敗した記述子を 1 つ分離するまで続行します。明らかに、偽の記述子が 1 つではなく複数ある場合は、このプロセスを数回繰り返す必要があります。

1 つの記述子を分離して、それに対して何をどのように行う必要があるかを決定できます。また、問題が再発した場合は、分離プロセスを繰り返すことができます。明らかに、最初に問題を検出しない限り、これを試しません。しかし、物事がうまくいかないときは、問題を切り分ける必要があり、これはそれを達成します (はずです)。

于 2011-11-21T15:52:45.290 に答える
0

別のスレッドでポーリングされていたソケット記述子で close() を実行していたことが判明しましたが、select() に基づくポーリングセットの実装はこれを好みません。一方、apr ライブラリ コードを変更して、select が無効なソケットを検出したときに記述子を返すようにすることも、自動的に削除することもできます。

于 2011-11-23T22:20:59.427 に答える