2011-11-30 45 views
1

我正在下载200个字符块中的在线.dat文件,并且一些数据丢失。大多数,但不是所有的块完全下载,但有些只是部分下载,当我将接收到的数据直接打印到本地文本文件时,缺少字符。使用C中的套接字在TCP传输中丢失数据

谢谢。

我正在使用的程序如下。

#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; 
    } 
+0

向我们展示'recv()'的实际代码。当然,你不是只调用一次? – NPE

+2

这是所有的代码?我看不到文件写入。 – hmjd

+0

'while(not_eof = NOT_EOF)'这是不对的。在C中,'='是赋值操作符。 –

回答

2

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

+0

对不起,我在程序中的其他地方收到了一个循环,所有的值都是正值,但数据丢失了。我会更新上述程序。 –

+0

@Julia你的更新没有意义。 'not_eof'在哪里改变?你如何汇总每个'recv'调用的输出结果? – Artefacto

+0

我已更新我的问题以在代码中显示请求的信息。 –

2

recv调用不保证在一次调用中接收所有数据。对于200字节的数据大小,人们可以期待整个数据在一次调用中,但并非总是如此。如果它不是全部在一次通话中收到,则需要再次调用recv。

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

+1

recv直到它到达文件的结尾,所以理论上如果我只收到每个recv数据的一半,最终我应该收到它的全部,但是有两倍的调用次数。但是,我收到的数据中的几个地方缺少实际字符。这会导致我另一个问题。是否有可能在接收数据方面不成功,并且数量有限,导致一些丢失的数据?我对这个主题了解不多,而且我可以在互联网上找到的信息页面都说TCP是可靠的。 –

+0

几乎100%保证了你的代码在某处的错误。 TCP是可靠的,并且大多数Web服务器也是如此。例如您需要仔细考虑recv的返回值。您应该向我们展示接收数据并将其写入文件的实际完整代码。 – nos

+0

我已更新我的问题以显示您在代码中请求的所有信息。 –