4

次の問題があります。コードのチャンクは次のとおりです。

void get_all_buf(int sock, std::string & inStr) {
    int n = 1;
    char c;
    char temp[1024*1024]; 

    bzero(temp, sizeof(temp));

    n = recv(sock, temp, sizeof(temp), 0);

    inStr = temp;
};

ただし、recvデータ全体ではなく (データ長は常に 未満sizeof(temp))、その一部のみを返す場合があります。書き込み側は常にデータ全体を送信します(スニファーで取得しました)。どうした?どうも。

PS私は知っています、良いマナーは私にチェックするように勧めますnif (n < 0) perror ("error while receiving data"))、しかしそれは今は問題ではありません-それは私の問題の理由ではありません.

PS2忘れました-ソケットをブロックしています。

4

3 に答える 3

11

TCP 標準では、データ パケットのフラグメント化が可能です。実際には、これは数百バイト程度の小さなデータ パケットでは発生しませんが、メガバイトのデータはほぼ確実に断片化されます。

第 2 に、スニファがすべてのデータが 1 つのパケットで送信されると言う場合、それとも複数のパケットで送信されると言う場合ですか?

適切なネットワーク プログラミングの実践では、メッセージが単一のチャンクで到着すると想定しないことが必要です。2 つの連続するメッセージが 1 つのパケットとして到着する可能性があり (理論的には、実際にはほとんどありません)、複数のパケットで到着した場合でも、1 回の読み取りとして読み取ることができます。1 つのメッセージが複数のパケットに断片化される可能性があり、すべてが一度に到着しない可能性があります。

プログラムはすべての読み取りをバッファリングし、区切り文字 (CRLFCRLF で区切られた HTTP ヘッダーなど) またはバイト カウント (長さがヘッダー) またはデータの終わりを示すために接続を閉じることによって (たとえば、コンテンツの長さがヘッダーで指定されていない場合の HTTP 本文)。他のメカニズムもあるかもしれません。

于 2010-12-22T13:25:22.407 に答える
6

はるかに良い方法は、次を使用することです。

void get_all_buf(int sock, std::string & output) {
    char buffer[1024];

    int n;
    while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) || 
          errno == EINTR)
    {
        if(n>0)
            output.append(buffer, n);
    } 

    if(n < 0){
        /* handle error - for example throw an exception*/
    }
};

また、スタックに割り当てられたバッファがはるかに小さいことに注意してください。スタックに 1M のバッファがあると、スタック オーバーフローが発生する可能性があります。

追記: おそらくソケットが閉じられるまで読みたくないので、while ループに別の終了条件を追加する必要があるかもしれません。

于 2010-12-22T13:34:45.037 に答える
3

TCP は、他の層 (IP とイーサネット) の上にある層として機能します。IP ではデータの断片化が可能であり、イーサネットでは一部のデータがネットワーク上で失われる可能性があります。これはデータの損失につながり、recv の呼び出しに反映されます。

を呼び出すとrecv、基になるオペレーティング システムは、指定されたサイズまで可能な限り多くのデータを読み取ろうとしますが、1 バイトでも読み取ったバイト数が少なくなる可能性があります。

データを読み込んでデータを完成させるには、独自のプロトコルを作成する必要があります。

たとえば、「\n」を区切り文字として使用できます。このコードは改善することができますが、アイデアが得られることを願っています:

void get_all_buf(int sock, std::string & inStr) {
    int n = 1, total = 0, found = 0;
    char c;
    char temp[1024*1024]; 

    // Keep reading up to a '\n'

    while (!found) {
        n = recv(sock, &temp[total], sizeof(temp) - total - 1, 0);
        if (n == -1) {
            /* Error, check 'errno' for more details */
            break;
        }
        total += n;
        temp[total] = '\0';
        found = (strchr(temp, '\n') != 0);
    }

    inStr = temp;
}
于 2010-12-22T13:46:26.497 に答える