recvmsg linux收到错误数据

Posted

技术标签:

【中文标题】recvmsg linux收到错误数据【英文标题】:recvmsg linux receive wrong data 【发布时间】:2013-07-18 18:23:36 【问题描述】:

我正在使用 recvmsg 和 sendmsg 通过异步 STREAM 套接字发送数据。要传输的数据量相当大,介于 15 MB 和 30 MB 之间。

我不明白为什么数据到达时已损坏。发送消息和接收功能被 errno EINTR 和 EAGAIN 中断。

我使用的功能是:

int receive_result_with_extra(int fd, struct syscall_result * result, int extra_size, char * buf)  
    struct iovec io[2];
    struct msghdr msg; 
    int transfered=0, temp=0; 
    const int total =  SIZE_RESULT + extra_size; 

    CLEAN_MSG(&msg);
    memset(io, 0, sizeof(io)); 

    // result header 
    io[1].iov_len=SIZE_RESULT; 
    io[1].iov_base=result;
    // result buffer
    io[0].iov_len = extra_size; 
    io[0].iov_base = buf; 
    // iov struct 
    msg.msg_iov=io;
    msg.msg_iovlen=2;

    do  
      temp = recvmsg(fd,&msg, 0);       
      if ( temp < 0 && (errno==EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) 
        continue; 
      else if ( temp < 0 )
          die("Error receiveing data recvmsg (receive_result_with_extra)"); 
      transfered += temp; 
     while(transfered < total); 

    if ( transfered < 0) 
        die("recvmsg (receive_result_with_extra)"); 

    assert(transfered == total);
    return transfered; 

int send_result_with_extra(int fd, struct syscall_result * result, int extra_size, char * buf) 

    struct iovec io[2];
    struct msghdr msg; 
    int transfered=0, temp=0; 
    const int total =  SIZE_RESULT + extra_size; 

    CLEAN_MSG(&msg);
    memset(io, 0, sizeof(io)); 

    // result header 
    io[1].iov_len=SIZE_RESULT; 
    io[1].iov_base=result;
    // result buffer
    io[0].iov_len = extra_size; 
    io[0].iov_base = buf; 
    // iov struct 
    msg.msg_iov=io;
    msg.msg_iovlen=2;

    do 
      temp=sendmsg(fd,&msg, 0); 
      if ( temp < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
          continue; 
      else if ( temp < 0)
          die("Failed sending data ( send_result_with_extra)");  
      transfered += temp; 
     while( transfered < total);

    if ( transfered < 0) 
        die("recvmsg (fstat handler)"); 

    assert(transfered == total);

    return transfered; 

【问题讨论】:

我怀疑为什么recvmsg(fd,&amp;msg, 0);中的最后一个参数0我认为应该是sizeof msg @GrijeshChauhan 不,这是正确的,这是一个标志值。 @JoachimPileborg 好的,这意味着 struct msghdr 是预定义的结构 套接字是否阻塞/非阻塞?您是否有任何信号处理程序被激活? “损坏”是什么意思? 【参考方案1】:

您不会在 send/recv 循环中更新 iovecs,因此如果数据太大而无法在单个网络数据包中传输,您将重复将相同的前缀/recv 发送到数据缓冲区的开头。

我会为发送和接收使用一个通用函数来更新iovec

/**
 * Shrinks the iovec associated with a msg by a given number of bytes.
 *
 * @msg    The message whose iovec needs updating.
 * @bytes  Number of bytes to remove from the beginning of the iovec.
 *
 * @return Returns 0 iff the updated iovec is empty.
 */
int update_buffer(struct msghdr* msg, size_t bytes) 
  while (msg->msg_iovlen > 0) 
    if (bytes < msg->msg_iov[0].iov_len) 
      msg->msg_iov[0].iov_len -= bytes;
      msg->msg_iov[0].iov_base += bytes;
      return 1;
    
    bytes -= msg->msg_iov[0].iov_len;
    ++msg->msg_iov;
    --msg->msg_iovlen;
  
  return 0;

然后,您可以在发送/接收循环的条件下使用此更新函数的返回值。例如:

do 
  do 
    temp = sendmsg(fd, &msg, 0); 
   while (temp < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
  if (temp < 0)
    die("Failed sending data (send_result_with_extra)");
 while (update_buffer(&msg, temp));

【讨论】:

我应该怎么做? @GiuseppePes 查看答案的补充。 @GiuseppePes Bah,发现另一个错误 - 我需要停止在答案中进行干编码。

以上是关于recvmsg linux收到错误数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Linux 中,recv() 有效,但 recvmsg() 无效

socket编程:recvmsg 和 sendmsg 函数

套接字之recvmsg系统调用

sendmsg 和 recvmsg 中的 iov 和 msg_control

套接字之recvfrom系统调用

tcp_recvmsg 函数具体解释