0

UNIX ローカル ソケットに問題があります。一時バッファ サイズよりも長いメッセージを読み込んでいるときに、リクエストに時間がかかりすぎます (場合によっては無期限に)。

いくつかのテストの後に追加: ::recv でのフリーズにまだ問題があります。(1023*8) バイト以下を UNIX ソケットに送信した場合 - すべて問題ありませんが、(1023*9) を超えて送信した場合 - recv コマンドでフリーズします。 おそらく、FreeBSD のデフォルトの UNIX ソケット制限または C++ のデフォルトのソケット設定でしょうか? 誰が知っていますか?


私はいくつかの追加テストを行い、::recv コマンドを実行し、メッセージ >= (1023*9) バイトの長さを読み取ろうとすると、最後の 9 回目の繰り返しで「フリーズ」することを 100% 確信しています。(最初の 8 回目の繰り返し g はうまくいきます。)

私がやっていること: アイデアは、ソケットから do/while ループを読み込むことです

::recv (current_socket, buf, 1024, 0);

bufSPECIAL SYMBOLをチェックします。見つからない場合:

  1. バッファの内容をマージするstringxxx += buf;
  2. bzero temp buf
  3. ::recv ループを続ける

while ループでリクエストに時間がかかりすぎる問題を修正するにはどうすればよいですか?

バッファをクリアするより良い方法はありますか? 現在、次のとおりです。

 char buf [1025];
 bzero(buf, 1025);

しかし、新しい C++ 標準では bzero が非推奨であることは知っています。

EDIT: * 「なぜバッファをきれいにする必要があるのですか*

この質問のコメントで質問が表示されます。バッファへの読み取りの次の(最後の)繰り返しでバッファのクリーンアップを行わないと、メッセージの最初の部分の「テール」が含まれます。

例:

 // message at the socket is "AAAAAACDE"
 char buf [6];
 ::recv (current_socket, buf, 6, 0); // read 6 symbols, buf = "AAAAAA"
 // no cleanup, read the last part of the message with recv
 ::recv (current_socket, buf, 6, 0); 
 // read 6 symbols, but buffer contain only 3 not readed before symbols, therefore
 // buf now contain "CDEAAA" (not correct, we waiting for CDE only)
4

4 に答える 4

1

無限ループに入った場合recv()、これはおそらく、反復で何も進行していないことを意味します(つまり、データを取得していないため、ループは常にゼロサイズの短い読み取りを取得しているため、ループが終了することはありません) )。ストリームソケットの場合、recv()サイズがゼロの場合は、リモートエンドが切断されていることを意味します(read()入力がEOFに配置されているときにファイルからingするようなものです)、または少なくとも送信チャネルをシャットダウンしていることを意味します(つまり、特にTCPの場合)。

PHPスクリプトが、送信すると主張する量のデータを実際に送信しているかどうかを確認します。

ループでrecv()を適切に使用するための小さな(無意味な)例を追加するには、次のようにします。

char buf[1024];
std::string data;
while( data.size() < 10000 ) { // what you wish to receive
    ::ssize_t rcvd = ::recv(fd, buf, sizeof(buf), 0);
    if( rcvd < 0 ) {
        std::cout << "Failed to receive\n";  // Receive failed - something broke, see errno.
        std::abort();
    } else if( !rcvd ) {
        break; // No data to receive, remote end closed connection, so quit.
    } else {
        data.append(buf, rcvd); // Received into buffer, attach to data buffer.
    }
}

if( data.size() < 10000 ) {
    std::cout << "Short receive, sender broken\n";
    std::abort();
}

// Do something with the buffer data.
于 2012-04-11T20:00:01.747 に答える
1

の代わりにbzero、そのまま使用できます

memset(buf, 0, 1025);
于 2012-04-11T14:25:55.847 に答える
1

明確にするために: bzeroC++ 11 では非推奨ではありません。むしろ、C または C++ 標準の一部ではありませんでした。Cは20年以上前に始まりましたmemset。C++ の場合は、std::fill_n代わりに を使用することを検討してください (またはstd::vector、自動的にゼロを埋めることができる を使用するだけです)。繰り返しになりますが、この場合、バッファーをゼロで埋める正当な理由があるかどうかはわかりません。

于 2012-04-11T14:41:03.010 に答える
1

これらは 2 つの別個の問題です。長い時間は、おそらくコードのバグによる無限ループであり、バッファをクリアする方法とは関係ありません。実際のところ、バッファをクリアする必要はありません。receiveは読み取ったバイト数を返すので、その時点までの SPECIAL_SYMBOL のバッファをスキャンできます。

コードを貼り付けていただければ、私がお手伝いできるかもしれません。もっと。

于 2012-04-11T14:30:30.090 に答える