【问题标题】:c++ how to use select to see if a socket has closedc ++如何使用select查看套接字是否已关闭
【发布时间】:2011-08-04 03:39:02
【问题描述】:

谁能提供一个示例,说明如何使用 select() 查看客户端是否关闭了套接字上的连接?

仅供参考。我用的是linux。

谢谢!

【问题讨论】:

  • 当连接被另一端关闭时,read 返回 0。

标签: c++ linux sockets select


【解决方案1】:

下面的 sn-p 首先检查套接字是否标记为可读(关闭时标记为可读),然后检查是否实际上有任何内容要读取。

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>

bool isclosed(int sock) {
  fd_set rfd;
  FD_ZERO(&rfd);
  FD_SET(sock, &rfd);
  timeval tv = { 0 };
  select(sock+1, &rfd, 0, 0, &tv);
  if (!FD_ISSET(sock, &rfd))
    return false;
  int n = 0;
  ioctl(sock, FIONREAD, &n);
  return n == 0;
}

【讨论】:

  • 我正在编写一个 telnet 服务器,并且它可以工作,但我没有在我的选择中执行“sock+1”。为什么需要这样做?
  • @James:这就是 API 的定义方式。
  • 如果一个简单的带有MSG_PEEK 标志的recv() 可以在一行中完成。
  • @user207421 问题是如何检查with select。这意味着此检查可能是多个其他事件的选择的一部分。使用recv() 不是this 问题的答案,而是解决不同问题的方法。
【解决方案2】:

您无需在select() 后面跟着ioctl()。您可以改为对套接字进行非阻塞窥视,看看它是否返回 0。

bool isclosed (int sock) {
    char x;
interrupted:
    ssize_t r = ::recv(sock, &x, 1, MSG_DONTWAIT|MSG_PEEK);
    if (r < 0) {
        switch (errno) {
        case EINTR:     goto interrupted;
        case EAGAIN:    break; /* empty rx queue */
        case ETIMEDOUT: break; /* recv timeout */
        case ENOTCONN:  break; /* not connected yet */
        default:        throw(errno);
        }
    }
    return r == 0;
}

【讨论】:

    【解决方案3】:

    如果您收到读取通知并且读取返回 0 字节,则客户端已完全退出。如果没有,您将收到异常通知。

    【讨论】:

    • 客户端已经干净地关闭了案卷,或者关闭了它的输出,或者在 UNIX 或 Linux 系统上干净地退出,但不是例如 Windws 系统,如果没有,您将收到 错误 指示。
    猜你喜欢
    • 2010-10-23
    • 1970-01-01
    • 1970-01-01
    • 2017-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-07
    • 1970-01-01
    相关资源
    最近更新 更多