1

新しく設計されたプロトコルを使用して 1 つのサーバーを実装しています。プロトコルに従って、クライアントはヘッダーに続いてデータを送信します。ヘッダーには、データのサイズなどのメタ情報も含まれています。

サンプルクライアントを提供していますが、クライアントプログラムはサードパーティでも作成できます。したがって、ヘッダーで提供されるデータ フィールドのサイズに完全に依存することはできません。

今、私はrecv()システムコールで1つの問題に直面しています。

      #define SOCKET_CHUNK_SIZE 4096
      void * value;

 1    value = (void *) malloc(hdr.size);
 2    total_bytes_read = 0;
 3    while(total_bytes_read < hdr.size) {
 4        n = recv(newsockfd, value + total_bytes_read, SOCKET_CHUNK_SIZE, 0);
 5
 6        //fprintf(stderr, " %ld + %d = %ld\n", total_bytes_read, n, total_bytes_read + n);
 7
 8        total_bytes_read += n;
 9
10        if(n == 0 || n < SOCKET_CHUNK_SIZE)
11            break;
12        if(n < 0)
13            send_error_response(newsockfd);
14    }
15
16    fprintf(stderr, "%ld", total_bytes_read);

これは、少量のデータ (9420 バイトなど) では完全に機能しますが、大量のデータでは失敗します。

観察:

クライアントが 604697 バイト (hdr.size) のような大量のデータを送信できるようにします。

  1. recv()65280 バイトしか読み取れません。つまり、16 行目の fprintf は 65280 を出力します。

  2. 呼び出しでMSG_DONTWAIT フラグを使用してみましrecv()たが、結果は同じです。

  3. read()の代わりにシステムコールを使用してみましたがrecv()、結果は同じです。

  4. 6行目のコメントを外すと、完全に機能します!! (ただし、この行 (および #16 行目) はデバッグ目的でのみ使用されます。最終バージョンでは保持できません)

  5. で MSG_WAITALL フラグを使用するrecv()と機能しますが、最後のチャンクのサイズが SOCKET_CHUNK_SIZE (604697 = 147 * 4096 + 2585) より小さいため、最後のチャンクの読み取り中にブロックされます。したがって、クライアントからのヘッダーで提供されるサイズに依存し、で変更しない限り、このフラグを使用できませんrecv()

クライアントから提供されるデータはバイナリの場合もあるため、データの終わりとして何らかの表示を配置することはできません。

アイデア/ソリューションをお持ちの方ならどなたでも大歓迎です。前述したように、クライアント ヘッダーに依存する解決策がありますが、他に方法が見つからない場合にのみそれを優先します。

ラヴィ

4

1 に答える 1

2

ほとんどすべての観察結果は完全に説明可能です。

  1. 正しいかどうかわからないのでスキップしたいと思います。また、今のところ二次的なエラーと考えているためです。
  2. (MSG_WAITALL を設定しない限り) recv がバッファ全体を埋める保証はありません。いくつかのバイトを受信した後に戻ります。したがって、行 10 の条件の 2 番目の部分は、MSG_WAITALL を設定しない場合、それ以上のデータを受信できないようにしています。MSG_WAITALL を設定すると、バッファー全体がいっぱいになった後にのみ recv が返されます (あなたの場合は SOCKET_CHUNK_SIZE)。ペイロードのサイズは常に SOCKET_CHUNK_SIZE の倍数ではないため、最後の recv 呼び出しは接続が切断されるまでハングします。
  3. これは、前述の 10 行目の条件によるものです。
  4. recv に固執します。これが正しい方法です。
  5. 行 6 のコメントを外すと、実行のタイミングが変更され、SOCKET_CHUNK_SIZE よりも多くのデータが偶然にソケットに到着するようになると思います。

したがって、私の観点からは、MSG_WAITALL フラグを指定せずに recv を使用し、SOCKET_CHUNK_SIZE より小さいチャンクの受信を受け入れることが最善の方法です。

于 2013-07-15T05:25:00.913 に答える