2011-06-13 124 views
12

我有一个问题,其中调用recv()系统调用不会阻止。我目前所面对的客户机 - 服务器结构设置,我有问题我向服务器发送一个消息,而服务器设置,以便它是这样的:C/C++套接字和非阻塞recv()

while (1) { 
    char buf[1024]; 
    recv(fd, buf, sizeof(buf), flags); 
    processMsg(buf); 
} 

它收到的第一条消息正确,但recv()不会阻止并“接收”不符合要求的垃圾数据。我只想在邮件发送时对邮件做出反应。任何人都可以建议吗?

+12

您最好检查'recv'的返回码。当你高兴地看着缓冲区中的一些垃圾时,它可以尖叫一个错误... – 2011-06-13 02:14:51

+1

你还需要考虑接收部分消息或更多字节的可能性,而不是一个消息的价值。如果发送者发送500字节的消息,则您的RECV呼叫可能只能检索200个字节,或者可能检索700个字节(如果您的发送者可以在不等待响应的情况下发送多条消息)。 – 2011-06-13 03:28:33

+0

在我之前的评论中应该包含一个指向[此TCP碎片讨论](http://stackoverflow.com/questions/4552855/tcp-fragmentation)的链接。 – 2011-06-13 03:35:03

回答

11

的recv()并不一定阻止,直到完整的请求得到满足,但可以返回部分请求。返回代码会通知您实际收到的字节数量可能少于您的要求。即使您指定了MSG_WAITALL标志,由于信号等原因它可能会返回更少。

在posix系统上,在阻止模式下,recv只会阻塞,直到有些数据存在才能读取。然后它将返回该数据,这可能比请求的数据少,达到所请求的数量。在非阻塞模式下,如果要读取零字节的数据,recv将立即返回,并将返回-1,将errno设置为EAGAIN或EWOULDBLOCK。

结果是,通常你会在回路中调用recv,直到你得到你想要的数量,同时还检查0(另一侧断开连接)或-1(一些错误)的返回码。

我不能说windows的行为。

12

有两种可能性:发生错误或将套接字设置为非阻塞模式。要查看是否发生错误时,检查recv返回值:

while() { 
    char buf[1024]; 
    int ret = recv(,buf,,) 

    if(ret < 0) { 
     // handle error 
     printf("recv error: %s\n", strerror(errno)); 
    } else { 
     // only use the first ret bytes of buf 
     processMsg(buf, ret); 
    } 
} 

为了把插座成非阻塞模式,或者查询如果套接字是非阻塞模式,使用fcntl(2)O_NONBLOCK标志:

// Test if the socket is in non-blocking mode: 
if(fcntl(sockfd, F_GETFL) & O_NONBLOCK) { 
    // socket is non-blocking 
} 

// Put the socket in non-blocking mode: 
if(fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK) < 0) { 
    // handle error 
} 

需要注意的是,除非你明确地改变了阻塞行为,插座应被默认阻止,所以最有可能发生错误时。

+3

第二条if语句中有一个错字(sockfg => sockfd) – MonoThreaded 2012-01-09 10:36:34

+3

这比接受的答案更有用... – Wolfer 2013-09-06 18:41:34