Отсутствие данных при передаче по TCP с использованием сокетов в C - PullRequest
1 голос
/ 30 ноября 2011

Я загружаю онлайн-файл .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;
    }

Ответы [ 2 ]

2 голосов
/ 30 ноября 2011

При вызове recv не гарантируется получение всех данных за один вызов.При размере данных в 200 байт можно ожидать, что все данные будут обрабатываться за один вызов, но это не всегда так.Если не все они были получены за один вызов, вам нужно было бы повторно вызвать recv.

Редактировать Изменения, как показано (если это реальный код), все еще кажутся необходимыми.Вызов fprintf выполняется независимо от возвращаемого значения.Таким образом, цикл выполняется дважды, а второй вызов recv завершился неудачно, буфер будет записан дважды.Кроме того, я не думаю, что buffer гарантированно завершается нулем, поэтому вызов fprintf(...%s...) может привести к непредсказуемым результатам.Похоже, однако, что основная проблема заключается в том, что возможность возврата значения -1 (случай ошибки) не обрабатывается.Теоретически это привело бы к бесконечному циклу.На самом деле, цикл будет бесконечным, как показано в текущий момент, независимо от того, что цикл while имеет одинаковые равные и назначит 1 флагу для каждой итерации (но я предполагаю, что это опечатка в редактировании).

2 голосов
/ 30 ноября 2011

Вы не можете позвонить recv только один раз. Поскольку вы находитесь в режиме блокировки, вы должны вызвать его в цикле и проверить, является ли его возвращаемое значение положительным. Если оно отрицательное, произошла ошибка, если оно равно нулю, сокет был корректно отключен.

...