2012-04-04 9 views
-1

私はC++を使用してクライアントサーバープログラムを開発しましたので、500kb以上を受信したいのですが、私のクライアントメッセージは "!"で終了します。 、私は私の最後のバイト(!)が受信するまで受信したいので、 これは私のコードですwork.whatそれと間違っていません。recv()を使用して大きなデータを受け取る方法は?

do 
    { 
    int num = recv(*csock, buf, bytesLeft,0); 

if (num == 0) 
{ 
    break; 
} 
else if (num < 0 && errno != EINTR) 
{ 
    fprintf(stderr, "Exit %d\n", __LINE__); 
    exit(1); 
} 
else if (num > 0) 
{ 
    numRd += num; 
    buf += num; 
    bytesLeft -= num; 
    fprintf(stderr, "read %d bytes - remaining = %d\n", num, bytesLeft); 
} 

    } 

    while (bytesLeft != 0); 
    fprintf(stderr, "read total of %d bytes\n", numRd); 
+3

1)非NUL終了バッファに対してstrcat()strlen()を使用しないでください。 2)CとC++を混在させない。3)診断出力は、stdoutではなくstderrに行かなければならない。 4)ありがとう。 – wildplasser

+0

あなたのソケットは_blocking_または_non-blocking_ですか?デフォルトでは、すべてのソケットはブロックされています。つまり、データが受信されない場合、より多くのデータが到着するのを待つ間に 'recv'の呼び出しが_block_します。 –

+0

経験則:使用しているすべてのコマンドのマニュアルを読んでください。 – hochl

答えて

1

あなたは内のすべてのデータ1MBの+が必要です1つの連続したバイトバッファ?そうであれば、そのプロトコルには「!」という終端記号が付いています。長さを含むヘッダーを持たない場合は、memcpy()とrealloc()でstd :: vectorのような多くのバッファー型がスタックされます。

これらのバイトをすべて1つの文字列にする必要がない場合は、他の方法で格納することができます。 * bufferのベクトルです。したがって、コピーは避けてください。

6

私はあなたの問題は、あなたの質問の文言である正確に何かわからないものの、ネットワークを介して受信しますが、特に彼らがなります知っている限り、あなたは一般的に、生のバッファを追加するstrcatを使用することはできませんnullで終了していても、予期せぬデータ転送が発生した場合でもそれは実際には「安全」ではありません。 c-stringを前提とすると、それらはNULLで終了しますが、未処理のネットワークバッファは存在しない可能性があります。strcatを使用すると、NULLで終わらないと入力バッファをオーバーランさせます。 strcatの代わりに、データを受信するためのサイズNバイトの既知の固定サイズのバッファを使用し、バッファの終わりまたはパケット転送の終わりに達するまでバッファを介して一時ポインタをインクリメントします。そうすれば、ネットワークから常にNバイト以上を読み込み、バッファオーバーランが発生するのを防ぐことができます。たとえば、次の操作を行うことができ

(これが原因で、すべてのコピーの最速以上の効率的なソリューションではありませんが、それは動作します):

unsigned char buf[10000]; //10Kb fixed-size buffer 
unsigned char buffer[MAXRECV]; //temporary buffer 

unsigned char* temp_buf = buf; 
unsigned char* end_buf = buf + sizeof(buf); 

do 
{  
    iByteCount = recv(GetSocketId(), buffer,MAXRECV,0); 

    if (iByteCount > 0) 
    { 
     //make sure we're not about to go over the end of the buffer 
     if (!((temp_buf + iByteCount) <= end_buf)) 
      break; 

     fprintf(stderr, "Bytes received: %d\n",iByteCount); 
     memcpy(temp_buf, buffer, iByteCount); 
     temp_buf += iByteCount; 
    } 
    else if (iByteCount == 0) 
    { 
     if(temp_buf != buf) 
     { 
      //do process with received data 
     } 
     else 
     { 
      fprintf(stderr, "receive failed"); 
      break; 
     } 
    } 
    else 
    { 
     fprintf(stderr, "recv failed: "); 
     break; 
    } 
} while(iByteCount > 0 && temp_ptr < end_buf); //check for end of buffer 
+0

私は10kbのデータを送信した場合を意味しますが、10kbのデータは6パケットに分割されているので、recv()を6回呼び出してから6回だけ呼び出したいので、データ全体を取得します。 –

+1

@ Mr.Cool - はい、バッファデータを連結する理由はわかっていますが、Jasonなどはstrcat()がその仕事をしないことを(正しく)言っています! –

+0

@ Martins James - それでは、データ全体をどのように入手できますか? –

1

(ソケットのデフォルトモードである)ブロッキングソケットを使用していると仮定すると、recv()は、完全なMAXRECVバイト数の到着を待つことをブロックします。クライアントがそのバイト数より少ないバイト数を送信すると、recv()は到着しないデータの待機をブロックします。あなたは!バイトに遭遇するまで

1)recv()を呼び出して、1バイトのバッファでrecv()を呼び出します。

は、その回避するには、次のいずれかにする必要があります。

2)はソケットが実際に読むためにデータを持っているときにそのバイト数を読みrecv()持って、実際にブロックすることなくrecv()で読み取ることができますどのように多くのバイト数を決定するためにioctlsocket(FIONREAD)を呼び出し、その後、検出するrecv()を呼び出す前にselect()を呼び出します。

関連する問題