在C中使用套接字丢失TCP传输中的数据

时间:2011-11-30 15:54:09

标签: c http sockets missing-data

我正在以200个字符块的形式下载一个在线.dat文件,但部分数据丢失了。大多数但不是所有的块都完全下载,但有些只是部分下载,当我将收到的数据直接打印到本地文本文件时,会丢失字符。

谢谢。

我正在使用的程序如下。

#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 个答案:

答案 0 :(得分:2)

你不能只召唤一次recv。由于您处于阻塞模式,因此必须在循环中调用它并检查其返回值是否为正。如果是负数,则出现错误,如果为零,则套接字有序关闭。

答案 1 :(得分:2)

recv电话无法保证在一次通话中接收所有数据。对于200字节的数据大小,可以预期一次调用中的整个数据,但情况可能并非总是如此。如果在一次通话中没有收到所有通话,则需要再次拨打recv。

编辑所显示的更改(如果是真实代码)似乎仍然需要工作。无论返回值如何,都会进行fprintf调用。因此,循环执行两次而第二次recv调用失败,缓冲区将被写入两次。此外,我不认为buffer被保证为空终止,因此fprintf(...%s...)调用可能会产生不可预测的结果。但是,似乎主要问题是没有处理返回值-1(错误情况)的可能性。从理论上讲,这会导致它无限循环。实际上,它会像当前显示的那样无限循环,因为while循环有一个等号并且每次迭代都会为该标志分配1(但我认为这是编辑中的拼写错误)。