9

私が書いたいくつかのサーバー コードでストレス テストを実施しているときに、記述子ハンドルで close() を呼び出している (そしてエラーの結果を検証している) にもかかわらず、記述子が解放されていないことに気付きました。エラー「開いているファイルが多すぎます」。

これは ulimit が原因であることがわかりました。理解できないのは、各同期の受け入れ/読み取り/送信サイクルの後に close() を呼び出すと、なぜそれが発生するのかということです。

lsof でウォッチを実行して、記述子が実際にそこにあることを検証しています。

ctsvr 9733 mike 1017u sock 0,7 0t0 3323579 プロトコルを識別できません
ctsvr 9733 mike 1018u sock 0,7 0t0 3323581 プロトコルを識別できません
...

そして確かにそれらの約1000かそこらがあります。さらに、netstat で確認すると、ハングしている TCP 状態がないことがわかります (WAIT や STOPPED などはありません)。

クライアントから単一の接続/送信/受信を実行すると、ソケットが lsof にリストされたままになることに気付きます。したがって、これは負荷の問題でもありません。

サーバーは Ubuntu Linux 64 ビット マシンで実行されています。

何かご意見は?

4

3 に答える 3

5

それで、strace(Gearoidに感謝)を使用して、私がこれまでどのように生きていたかわからないので、私は実際に記述子を閉じていることに気づきました。

でも。そして後世のために、私は愚かな過ちを露呈しました:

Socket::Socket() : impl(new Impl) {
    impl->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    ....
}

Socket::ptr_t Socket::accept() {
    auto r = ::accept(impl->fd, NULL, NULL);
    ...
    ptr_t s(new Socket);
    s->impl->fd = r;
    return s;
}

ご覧のとおり、コンストラクターはすぐにソケットを割り当て、次に記述子をacceptによって返されたものに置き換えました-リークを作成しました。これを変更せずに、スタンドアロンのAcceptorクラスからSocketクラスにacceptコードをリファクタリングしました。

straceを使用すると、毎回socket()が実行されているのが簡単にわかり、電球の瞬間につながります。

助けてくれてありがとう!

于 2012-10-12T05:28:03.230 に答える
1

close() の後に perror() を呼び出したことはありますか? 返された文字列が役立つと思います。

于 2012-10-15T03:46:32.200 に答える
0

recv()またはsend()コマンドでハングアップしている可能性があります。を使用してタイムアウトを設定することを検討してくださいsetsockopt

recv()ソケットが反対側で閉じられたときに lsof で同様の出力に気付きましたが、私のスレッドはデータを待っているコマンドでソケットを開いたままにしていました。

于 2012-10-10T14:24:08.563 に答える