2013-07-18 3 views
1

recvmsg 및 sendmsg를 사용하여 비동기 STREAM 소켓을 통해 데이터를 전송합니다. 전송할 데이터의 양은 15MB에서 30MB 사이에서 상당히 큽니다.recvmsg linux 잘못된 데이터 수신

왜 데이터가 손상되었는지 이해할 수 없습니다. 보내는 메시지와 reciving 함수는 errno EINTR 및 EAGAIN에 의해 ​​인터럽트됩니다. 내가 사용 석사

기능은 다음과 같습니다 반복적으로 데이터 버퍼 경우의 시작 부분에 같은 접두사/RECV를 보낼 수 있도록

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

나는 의심의 여지 왜 recvmsg'의 마지막 인수'0' (FD, MSG, 0);'나는 그것이를 sizeof msg' –

+0

@GrijeshChauhan 아니 그것, 그것은 맞습니다 것 플래그 값 '해야한다고 생각합니다. –

+0

@JoachimPileborg는'struct msghdr'가 미리 정의 된 구조체임을 의미합니다. –

답변

3

당신은, 당신의 전송/RECV 루프에서 iovecs를 업데이트하지 데이터가 너무 커서 단일 네트워크 패킷으로 전송할 수 없습니다.

나는 모두 전송을위한 공통 기능을 사용하고이 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; 
} 

당신은 다음 보내기/RECV 루프의 조건이 업데이트 함수의 반환 값을 사용할 수 있습니다. 예컨대 :

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)); 
+0

어떻게해야합니까? –

+0

@GiuseppePes 답변 추가를 참조하십시오. – Casey

+0

@GiuseppePes Bah, 다른 버그를 찾았습니다. 응답 코드에서 드라이 코딩을 중단해야합니다. – Casey