【问题标题】:Missing Data in TCP Transmission Using Sockets In C使用 C 中的套接字在 TCP 传输中丢失数据
【发布时间】:2011-11-30 15:54:08
【问题描述】:

我正在下载一个包含 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;
    }

【问题讨论】:

  • 向我们展示recv() 周围的实际代码。你确定不是只调用一次吗?
  • 这就是全部代码吗?我没有看到文件写入。
  • while(not_eof=NOT_EOF) 这不可能。在 C 中,= 是赋值运算符。

标签: c http sockets missing-data


【解决方案1】:

您不能只调用一次recv。由于您处于阻塞模式,因此您必须循环调用它并检查其返回值是否为正。如果为负数,则表示有错误,如果为0,则socket已被有序关闭。

【讨论】:

  • 对不起,我确实在程序的其他地方循环接收,所有值都是正数,但数据丢失。我会更新上面的程序。
  • @Julia 你的更新毫无意义。 not_eof 哪里改了?如何从每个recv 调用的输出中组合结果?
  • 我已更新我的问题以在代码中显示请求的信息。
  • @Julia 那fprintf(testdata,"%s",buffer); 是错误的。首先,可能有错误,buffer 可能是垃圾,其次,您必须准确写入您在该迭代中收到的字节数,例如 fwrite(buffer, 1, bytes_received, testdata)
【解决方案2】:

recv 调用不能保证在一次调用中接收所有数据。对于 200 字节的数据大小,人们会期望在一次调用中获取全部数据,但情况并非总是如此。如果一次通话未全部收到,则需要再次调用 recv。

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

【讨论】:

  • 我一直调用 recv 直到它到达文件末尾,所以理论上如果我只收到每个 recv 中一半的数据,最终我应该收到所有数据,但调用次数是两倍。但是,在我收到的数据中,有几个地方缺少实际字符。这将导致我提出另一个问题。是否有可能接收数据不成功,尝试次数有限导致一些数据丢失???我对这个话题了解不多,在网上只能找到说TCP可靠的信息页。
  • 几乎 100% 保证您的代码中的某个地方存在错误。 TCP 是可靠的,大多数 Web 服务器也是如此。例如,您需要仔细考虑 recv 的返回值。您应该向我们展示接收数据并将其写入文件的实际完整代码。
  • 我已更新我的问题以显示您在代码中请求的所有信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-24
  • 2017-05-30
  • 2019-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多