0

更新:詳細を調査した結果、この動作の本当の問題を発見しました。問題は、接続ごとにスレッドを作成し、sock fd をスレッドに渡していますが、すぐに pthraed_joining しなかったため、接続の受け入れ後にメインスレッドがそれ以上スレッドを作成できなくなったことです。ソケットを閉じる私のロジックは子スレッドにあります。そのため、ソケットを閉じることができなかったため、WAIT CLOSE状態になりました。だから私はそれらを作成した後にスレッドを切り離しただけで、今のところすべてうまくいきます!!

クライアントサーバープログラムがあり、スクリプトを使用してクライアントを実行し、可能な限り多くの接続を作成し、データ行を送信してクライアントを終了した後、それらを閉じます.32739番目の接続、つまり接続が閉じられるまで、すべてが正常に機能します両側とすべてを除いて、その数の後、接続は閉じられず、サーバーはそれ以上の接続の取得を停止します。

netstat -tonpa 2>&1 | grep CLOSE

約 1020 個のソケットが CLOSE を待っています。コマンドからのサンプル、

tcp 25 0 192.168.0.175:16099 192.168.0.175:41704 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0)
tcp 24 0 192.168.0.175:16099 192.168.0.175:41585 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0)
tcp 30 0 192.168.0.175:16099 192.168.0.175:41679 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0)
tcp 31 0 192.168.0.175:16099 192.168.0.175:41339 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0)
tcp 25 0 192.168.0.175:16099 192.168.0.175:41760 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0)

次のコードを使用して、クライアントの切断を検出しています。

for(fd = 0; fd <= fd_max; fd++) {
    if(FD_ISSET(fd, &testfds)) {
       if (fd == client_fd) {
           ioctl(fd, FIONREAD, &nread);
           if(nread == 0) {
               FD_CLR(fd, &readfds);
               close(fd);
               return 0;
           }
       }
    }
} /* for()*/

何か間違ったことをしている場合はお知らせください。Python クライアントと CPP サーバーのセットアップです。

ありがとうございました

4

2 に答える 2

2

CLOSE-WAIT は、ポートがローカル アプリケーションがソケットを閉じるのを待っていることを意味し、ピアからのクローズを既に受信しています。おそらくエラーパスで、何らかの方法でソケットをリークしていることは明らかです。

「クライアントの切断を検出する」コードは完全に間違っています。テストしているのは、ブロックせずに読み取ることができるデータの量、つまり既に到着したデータの量だけです。正しいテストは、recv() からのゼロの戻り値、または読み取りまたは書き込み時の EAGAIN/EWOULDBLOCK 以外のエラーです。

于 2013-07-12T23:58:29.740 に答える
1

あなたのプラットフォームを知らなければ、私には確信が持てませんが、あなたが明らかに を使用してselectおり、32768 からわずか数ダース離れたところで問題が発生しているという事実を考えると、これがあなたの問題である可能性が非常に高いと思われます。

Anfd_setは、ファイル記述子番号によってインデックス付けされたビットのコレクションです。プラットフォームごとに最大数が異なります。OpenBSD および最近のバージョンの FreeBSD と OS X では、通常、fd_setFD_SETSIZEがデフォルトの 1024 に制限されています。別の Linux ボックスには、1024、4096、32768、および 65536 があるようです。

FD_ISSET(32800, &testfds)では、あなたFD_SETSIZEが 32768 の場合はどうなるでしょうか。任意のメモリからビットを読み取るように要求しています。

パラメータに 32800 を渡すと、これより前にまたは他の呼び出しで EINVAL エラーが発生するはずselectですnfds、歴史的に、多くのプラットフォームではそうしていません。または、エラーが返されましたが、最初のFD_SETSIZEビットを適切に入力し、残りを初期化されていないメモリに設定した後でのみ、エラーを確認するのを忘れた場合、コードを強調するまでコードが機能しているように見えます。

これがselect、数百を超えるソケットを使用することが悪い考えである理由の 1 つです。もう1つの理由は、それselectが線形であることです(さらに悪いことに、現在のソケットの数では線形ではなく、最大のfdで線形であるため、ほとんどのクライアントがなくなった後でもまだ遅いです)。

を備えている最新のプラットフォームのほとんどselectpoll、その問題を回避します。

Windows を使用していない限り…その場合、使用しない理由はまったく異なりselect、答えも異なります。

于 2013-07-12T23:58:52.167 に答える