C/C++套接字和非阻塞recv()

13

我遇到了一个问题,即调用recv()系统调用不会阻塞。目前我正在设置一个客户端-服务器结构,我遇到的问题是我发送了一条消息给服务器,而服务器则是这样设置的:

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

它可以正确地接收第一条消息,但是recv()不会阻塞并"接收"垃圾数据,这不是想要的结果。我希望只在发送消息时才对其进行反应。有人能给予建议吗?


13
你最好检查一下recv的返回代码。否则当你愉快地查看缓冲区中的某些垃圾时,它可能会因错误而大声尖叫。 - user405725
1
你还需要考虑到接收到部分消息或者超过一个完整消息的字节数的可能性。如果发送方传输的是500字节的消息,你的RECV调用可能只会检索到200字节,或者它可能会检索到700字节(如果发送方可以在等待响应的情况下传输多个消息)。 - Frank Boyne
我之前的评论应该包含一个指向TCP分段讨论的链接。 - Frank Boyne
3个回答

21

recv()不一定会在完整请求被满足之前阻塞,但可能会返回部分请求。 返回代码将通知您实际接收到的字节数,这可能少于您请求的字节数。 即使您指定了MSG_WAITALL标志,由于信号等原因它也可以返回较少数量的数据。

在posix系统上,在阻塞模式下,recv仅会阻塞直到有一些数据可供读取。 然后它将返回该数据,该数据可能小于所请求的数据,最多达到请求的数量。 在非阻塞模式下,如果没有字节数据可供读取,则recv将立即返回并返回-1,将errno设置为EAGAIN或EWOULDBLOCK。

总之,通常情况下,您会调用recv循环直到获得所需的数量,同时还会检查返回码是否为0(另一方已断开连接)或-1(某些错误)。

我不能确定Windows的行为。


18

有两种可能性:一是发生了错误,二是套接字被设置为非阻塞模式。要查看是否发生错误,请检查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
还有两种可能性:流的结束或部分消息。你的代码没有检查前者。 - user207421

1

3
除非recv返回-1,否则它们都没有意义。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接