在阻塞式的tcp连接中使用recv接收数据未达到指定长度返回问题

 转自http://naso.iteye.com/blog/1927483

 一直以为在阻塞的tcp socket上使用read/recv读取的数据长度一定和指定的读取长度一致,但是实际测试时发现往往返回的长度都比指定长度短,查找资料发现其实是一直误解了这个函数。 

  引用《UNIX网络编程 卷一 套接字联网API》3.9中的说法: 
字节流套接口(如tcp套接口)上的read和write函数所表现的行为不同于通常的文件IO。字节流套接口上的读或写输入或输出的字节数可能比要求的数量少,但这不是错误状况,原因是内核中套接口的缓冲区可能已达到了极限。此时所需的是调用者再次调用read或write函数,以输入或输出剩余的字节。 

  书中给出了readn和writen函数解决这个问题。 
C代码   收藏代码
  1. ssize_t      /* Read "n" bytes from a descriptor. */  
  2. readn(int fd, void *vptr, size_t n)  
  3. {  
  4.  size_t nleft;  
  5.  ssize_t nread;  
  6.  char *ptr;  
  7.   
  8.  ptr = vptr;  
  9.  nleft = n;  
  10.  while (nleft > 0) {  
  11.   if ( (nread = read(fd, ptr, nleft)) < 0) {  
  12.    if (errno == EINTR)  
  13.     nread = 0;  /* and call read() again */  
  14.    else  
  15.     return(-1);  
  16.   } else if (nread == 0)  
  17.    break;    /* EOF */  
  18.   
  19.   nleft -= nread;  
  20.   ptr   += nread;  
  21.  }  
  22.  return(n - nleft);  /* return >= 0 */  
  23. }  

C代码   收藏代码
  1. ssize_t      /* Write "n" bytes to a descriptor. */  
  2. writen(int fd, const void *vptr, size_t n)  
  3. {  
  4.  size_t  nleft;  
  5.  ssize_t  nwritten;  
  6.  const char *ptr;  
  7.   
  8.  ptr = vptr;  
  9.  nleft = n;  
  10.  while (nleft > 0) {  
  11.   if ( (nwritten = write(fd, ptr, nleft)) <= 0) {  
  12.    if (nwritten < 0 && errno == EINTR)  
  13.     nwritten = 0;  /* and call write() again */  
  14.    else  
  15.     return(-1);   /* error */  
  16.   }  
  17.   
  18.   nleft -= nwritten;  
  19.   ptr   += nwritten;  
  20.  }  
  21.  return(n);  
  22. }  

  在13.3中提供了另外一个选择: 
  在recv中,可以使用MSG_WAITALL标志保证要求读取的字节数。即使使用了MSG_WAITALL标志,如果发生了下列情况:(a)捕获一个信号(b)连接被终止,或(c)在套接口上发生错误,这个函数返回的字节数仍会比请求的少。 
  而且要注意的是这个标志并不是每个版本的recv都会实现的。

你可能感兴趣的:(socket)