1

オンラインの .dat ファイルを 200 文字のチャンクでダウンロードしていますが、一部のデータが欠落しています。すべてではありませんがほとんどのチャンクが完全にダウンロードされますが、一部のチャンクは部分的にしかダウンロードされず、受信したデータをローカルのテキスト ファイルに直接出力すると、文字が欠落します。

ありがとうございました。

私が使用しているプログラムは以下です。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netdb.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <malloc.h>

#define NOT_EOF  1
#define REACHED_EOF 0
#define BUFFER_SIZE 200

struct sockaddr_storage their_addr;
socklen_t addr_size;
char inputData[200];
int newsocket;
struct timeval timeout;
char sendStr[100]; 
char method[] = "GET";

char *buffer= (char *)malloc(2*BUFFER_SIZE*sizeof(char));

FILE *testdata=fopen("testRecv.txt","w");

struct addrinfo hints, *result;
memset (&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;

if(getaddrinfo("www.blahblah.com","80"
                  , &hints, &result)!=0)
{
     freeaddrinfo(result);
     puts("Unable to resolve hostname.");
     exit(1);
 }

 newsocket = socket( result->ai_family, result->ai_socktype, 0);
 if(newsocket == FAILURE)
 {
    puts("Unable to create socket.");
    freeaddrinfo(result);
    close(newsocket);
    exit(1);
  }

 memset(&timeout, 0, sizeof(timeout));
 timeout.tv_sec= 10;
 timeout.tv_usec= 0;
 setsockopt(newsocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
 setsockopt(newsocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

if(connect(newsocket, result->ai_addr, result->ai_addrlen) == -1)
  {
    puts("Could not connect.");
    freeaddrinfo(result);
    close(newsocket);
   exit(1);
  }

strcpy(sendStr,method);
strcat(sendStr," /");
strcat(sendStr,subdomain);
strcat(sendStr," HTTP/1.0\r\nHost: ");
strcat(sendStr,hostname);
strcat(sendStr,"\r\n\r\n");

if( send(newsocket,sendStr,strlen(sendStr),0) == FAILURE)
 printf("Unable to send message\n");

 while(not_eof=NOT_EOF)
   {
       bytes_recieved=recv(newsocket,buffer,BUFFER_SIZE,0);

       fprintf(testdata,"%s",buffer);

       if(bytes_recieved == 0 || *(buffer+bytes_recieved) == EOF)
       not_eof=REACHED_EOF;
    }
4

2 に答える 2

2

recv呼び出しは、1 回の呼び出しですべてのデータを受信する保証はありません。200 バイトのデータ サイズの場合、1 回の呼び出しでデータ全体が期待されますが、常にそうであるとは限りません。1 回の呼び出しですべてが受信されなかった場合は、recv を再度呼び出す必要があります。

編集示されている変更 (実際のコードの場合) は、まだ作業が必要なようです。fprintf 呼び出しは、戻り値に関係なく行われます。したがって、ループが 2 回実行され、2 回目の recv 呼び出しが失敗した場合、バッファーは 2 回書き込まれます。また、null で終了することが保証されているとは思わないbufferため、fprintf(...%s...)呼び出しは予測できない結果になる可能性があります。ただし、主な問題は、戻り値が -1 になる可能性 (エラーの場合) が処理されないことです。理論的には、それは無限ループになります。実際には、whileループには単一の等号があり、反復ごとにフラグに 1 が割り当てられるため、現在示されているように無限にループします (ただし、これは編集のタイプミスだと思います)。

于 2011-11-30T16:04:29.437 に答える
2

1回だけ電話することはできませんrecv。ブロッキング モードであるため、ループ内で呼び出して、戻り値が正かどうかを確認する必要があります。負の場合はエラーが発生し、ゼロの場合はソケットが正常にシャットダウンされています。

于 2011-11-30T16:00:28.050 に答える