C中使用套接字的TCP传输中缺少数据

C中使用套接字的TCP传输中缺少数据,c,http,sockets,missing-data,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> #incl

我正在下载一个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;
    }
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义不为1
#定义0的到达时间
#定义缓冲区大小为200
结构sockaddr\u存储它们的地址;
袜子尺寸;
字符输入数据[200];
int newsocket;
结构timeval超时;
char-sendStr[100];
char方法[]=“GET”;
char*buffer=(char*)malloc(2*buffer_SIZE*sizeof(char));
文件*testdata=fopen(“testRecv.txt”、“w”);
结构addrinfo提示,*结果;
memset(提示和提示,0,提示大小);
hits.ai_family=AF_INET;
hits.ai_socktype=SOCK_流;
如果(getaddrinfo(“www.blahblah.com”,“80”)
,提示和结果)!=0)
{
freeaddrinfo(结果);
puts(“无法解析主机名”);
出口(1);
}
newsocket=socket(结果->ai_族,结果->ai_socktype,0);
if(newsocket==失败)
{
puts(“无法创建套接字”);
freeaddrinfo(结果);
关闭(newsocket);
出口(1);
}
memset(&timeout,0,sizeof(timeout));
超时。电视秒=10;
超时。tv_usec=0;
setsockopt(newsocket、SOL_SOCKET、SO_SNDTIMEO和timeout、sizeof(timeout));
setsockopt(newsocket、SOL_SOCKET、SO_RCVTIMEO和timeout、sizeof(timeout));
如果(连接(newsocket,result->ai_addr,result->ai_addrlen)=-1)
{
puts(“无法连接”);
freeaddrinfo(结果);
关闭(newsocket);
出口(1);
}
strcpy(sendStr,方法);
strcat(sendStr,“/”);
strcat(sendStr,子域);
strcat(sendStr,“HTTP/1.0\r\nHost:”;
strcat(sendStr,主机名);
strcat(sendStr,“\r\n\r\n”);
if(发送(newsocket,sendStr,strlen(sendStr),0)=失败)
printf(“无法发送消息\n”);
while(not_eof=not_eof)
{
接收的字节数=recv(newsocket,buffer,buffer\u SIZE,0);
fprintf(测试数据,“%s”,缓冲区);
如果(接收字节==0 | |*(缓冲区+接收字节)==EOF)
not_eof=达到_eof;
}

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

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

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


编辑如图所示的更改(如果是真正的代码)似乎仍然需要修改。无论返回值如何,都会进行fprintf调用。因此,循环执行两次,第二个recv调用失败,缓冲区将被写入两次。另外,我不认为
缓冲区
保证以null结尾,因此
fprintf(…%s…)
调用可能会产生不可预测的结果。不过,主要问题似乎是没有处理返回值为-1(错误情况)的可能性。理论上,这将导致它无限循环。实际上,它将无限循环,正如当前显示的那样,因为
while
循环有一个equals,并且每次迭代都将为标志分配1(但我假设这是编辑中的一个输入错误)。recv
调用不保证在一次调用中接收所有数据。对于200字节的数据大小,人们期望在一次调用中获得全部数据,但情况并非总是如此。如果在一次呼叫中未全部收到,则需要再次呼叫recv


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

显示
recv()周围的实际代码。你肯定不会只打一次电话吗?这是所有的密码吗?我看不到文件写入。
while(not_eof=not_eof)
这不可能是正确的。在C语言中,
=
是赋值运算符。显示
recv()
周围的实际代码。你肯定不会只打一次电话吗?这是所有的密码吗?我看不到文件写入。
while(not_eof=not_eof)
这不可能是正确的。在C语言中,
=
是赋值运算符。很抱歉,我在程序的其他地方有一个循环中的receive,所有的值都是正数,但缺少数据。我将更新上述程序。@Julia您的更新毫无意义。
在哪里没有更改?如何从每个
recv
调用的输出中汇编结果?我已经更新了我的问题,以在代码中显示请求的信息。@Julia That
fprintf(testdata,“%s”,buffer)是错误的。首先,可能存在错误,
buffer
可能是垃圾,其次,您必须准确地写入在该迭代中收到的字节数,因此类似于
fwrite(buffer,1,bytes