【问题标题】:C/C++ sockets and a non-blocking recv()C/C++ 套接字和非阻塞 recv()
【发布时间】:2011-09-13 15:22:14
【问题描述】:

我遇到了调用 recv() 系统调用不会阻塞的问题。我目前有一个客户端-服务器结构设置,我遇到的问题是我向服务器发送一条消息,而服务器已设置为如下所示:

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

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

【问题讨论】:

  • 您最好检查来自recv 的返回码。当您高兴地查看缓冲区中的一些垃圾时,它可能会尖叫错误...
  • 您还需要考虑接收部分消息或超过一条消息价值的字节的可能性。如果发件人传输 500 字节的消息,您的 RECV 调用可能只检索 200 个字节,或者它可能检索 700 个字节(如果您的发件人可以在不等待响应的情况下传输多条消息)。
  • 应该在我之前的评论中包含指向this discussion of TCP Fragmentation 的链接。

标签: c++ c sockets


【解决方案1】:

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

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

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

我无法谈论 Windows 行为。

【讨论】:

    【解决方案2】:

    有两种可能:要么发生错误,要么套接字设置为非阻塞模式。要查看是否发生错误,请检查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
    }
    

    请注意,除非您明确更改阻塞行为,否则默认情况下套接字应该是阻塞的,因此很可能会发生错误。

    【讨论】:

    • 第二个if语句有错别字(sockfg => sockfd)
    • 还有两种可能性:流结束或部分消息。您的代码不会检查前者。
    【解决方案3】:

    如果您在 Windows 上,请运行 wsagetlasterror() 函数并查看返回值。

    http://msdn.microsoft.com/en-us/library/ms741580%28v=vs.85%29.aspx

    如果您使用的是 posix 兼容系统,请查看 errno

    http://pubs.opengroup.org/onlinepubs/009695399/functions/errno.html

    【讨论】:

    • 这两个都是没有意义的,除非recv返回-1。
    猜你喜欢
    • 2010-10-29
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 2011-12-27
    相关资源
    最近更新 更多