从TCP套接字读取错误的数据

时间:2012-11-06 08:38:06

标签: c linux sockets networking tcp

我正在尝试通过TCP套接字逐块发送数据。服务器代码执行以下操作:

#define CHECK(n) if((r=n) <= 0) { perror("Socket error\n"); exit(-1); }
int r;

//send the number of blocks
CHECK(write(sockfd, &(storage->length), 8)); //p->length is uint64_t

for(p=storage->first; p!=NULL; p=p->next) {
  //send the size of this block
  CHECK(write(sockfd, &(p->blocksize), 8)); //p->blocksize is uint64_t

  //send data
  CHECK(write(sockfd, &(p->data), p->blocksize));
}

在客户端,我读取大小,然后读取数据(相同的CHECK makro):

CHECK(read(sockfd, &block_count, 8));
for(i=0; i<block_count; i++) {
  uint64_t block_size;
  CHECK(read(sockfd, &block_size, 8));

  uint64_t read_in=0;
  while(read_in < block_size) {
    r = read(sockfd, data+read_in, block_size-read_in); //assume data was previously allocated as char*
    read_in += r;
  }
}

只要客户端和服务器都在同一台机器上运行,这种方法就可以正常运行,但只要我通过网络尝试这一点,就会在某些时候失败。特别是,前300-400块(~~ 587字节)左右工作正常,但后来我得到了一个不正确的block_size读数:

received block #372 size : 586
read_in: 586 of 586
received block #373 size : 2526107515908

然后它显然崩溃了。 我的印象是,TCP协议确保没有数据丢失,所有内容都按正确的顺序接收,但那么这是怎么可能的,这是我的错误,考虑到它已经在本地工作了?

4 个答案:

答案 0 :(得分:4)

当您阅读block_countblock_size时,无法保证一次性读取所有8个字节。

答案 1 :(得分:1)

  

我的印象是TCP协议确保没有数据   丢失,一切都以正确的顺序收到

是的,但这就是TCP的保证。它不保证数据在单个数据包中发送和接收。您需要收集数据并将它们放在缓冲区中,直到在复制数据之前获得所需的块大小。

答案 2 :(得分:1)

读取调用可能在没有读取完整的8个字节的情况下返回。我会查看他们报告的读长度。

您可能还会发现valgrind或strace提供信息,以便更好地理解代码以这种方式运行的原因。如果你得到简短的读取,strace会告诉你系统调用返回的是什么,valgrind会告诉你你正在读取长度变量中未初始化的字节。

答案 3 :(得分:1)

它在同一台机器上工作的原因是block_size和block_count是作为二进制值发送的,当它们被客户端接收和解释时,它们具有相同的值。

但是,如果两台通信机器具有不同的字节顺序来表示整数,例如x86与SPARC或sizeof(int)不同,例如64位与32位,则代码将无法正常工作。

您需要验证两台机器的sizeof(int)和字节顺序是否相同。在服务器端,打印出sizeof(int)和storage-&gt; length和p-&gt; blocksize的值。在客户端打印出sizeof(int)和block_count和block_size的值。

当它无法正常工作时,我认为你会发现它们不一样。如果这是真的,那么如果数据包含任何二进制数据,那么数据的内容也会被误解释。