6

Cのソケットを介していくつかのファイルを受信しようとしています。しかし、サーバーは、たとえば1000000バイトのファイルに対して64バイトのパケットを送信し、宛先ファイルで約999902バイトを取得します。

while ((n = read(sd, buffer_in, BUFSIZE ))) //  BUFSIZE = 64 
{
    if(n<0)
    {
       printf("Fail.\n");
       fclose(archivo);
       return -1;
    }

    if(fwrite(buffer_in, n, 1, f) !=1 ) 
    { 
       printf("fwrite error.\n");
       fclose(archivo);
       return -1;
    }

    bytes+=n;
}

printf("We received %d bytes",  bytes);

ローカルTCP/IPソケットを介して使用すると機能しますが、低速接続では機能しません。デバッグを通して、64バイトのチャンクがたくさんあり、EOFの近くに30バイトのチャンクがあることがわかります。データ(> 1バイト)が使用可能になると呼び出しが返されるため、read()で取得できるバイト数が少なくなることはわかっています。しかし、この状態はしばらくの間捕らえられるべきではありませんか?n == 0のときに戻る必要があります。これは、データ(EOF)ではありません。

あなたの助けのためのThx。

(編集)

次のようにコードを送信します。

while (n=read(file_fd, buffer, BUFSIZE))
{
   write (sdaccept, buffer, n)
}

read()とwrite()の両方がN <BUFSIZEを返す可能性があることは知っていますが、このループはそれに応じてそれを解決するべきではありませんか?nを合計すると、正確なサイズである1000000が返されます。

(編集II)

10673バイトのCソースでテストされ、宛先ファイルが最初の98バイトを欠いていることを除いて、破損することなく10575を受け取ります!!!

4

1 に答える 1

11

提供された送信コードは、ソケットの write() (または send() ) がバッファ全体を書き込む義務がないという事実を無視しています。

write()/send() は、基礎となるサブシステムがそれ以上のデータの受信を拒否した場合、部分的に書き込むか、まったく書き込まないかを決定する場合があります (たとえば、ネットワーク サブシステムに送信するデータのキューがあり、このキューが既にいっぱいである場合など)。これは、接続が遅い場合に発生する可能性が非常に高いです。

送信側は write() の戻り値をチェックして、実際に書き込まれたデータの量を検出し、それに応じて調整する必要があります。

書き込みは、次のように行う必要があります。

int readAmount;
while( readAmount = read(file_fd, buffer, BUFSIZE) > 0 )
{
    int totalWritten = 0;
    do {
       int actualWritten;
       actualWritten = write (sdaccept, buffer + totalWritten, readAmount - totalWritten);
       if( actualWritten == - 1 ) {
           //some error occured - quit;
       }
       totalWritten += actualWritten;
    } while( totalWritten < readAmount );
}
于 2009-03-26T06:56:35.853 に答える