【问题标题】:Linux: Checking if a socket/pipe is broken without doing a read()/write()Linux:在不执行 read()/write() 的情况下检查套接字/管道是否损坏
【发布时间】:2012-02-09 14:02:16
【问题描述】:

我有一段简单的代码,它定期将数据写入传递给它的 fd。 fd 很可能是管道或套接字,但也可能是任何东西。每当我 write() 时,我都可以检测到套接字/管道何时关闭/损坏,因为我收到 EPIPE 错误(我忽略了 SIGPIPE)。但我不会一直写信给它,所以可能很长一段时间都检测不到关闭的套接字。我需要尽快对关闭做出反应。有没有一种无需执行 write() 即可检查 fd 的方法?如果我不写任何东西,我可以定期执行此操作。

【问题讨论】:

  • select、poll、epoll都会告诉你
  • 感谢您的回答,但我不确定如何使用管道进行此操作。我已经尝试在写入中使用我的 fd 进行 select() 调用,但 fdset 除外,并且当管道损坏时调用的结果不会改变(总是在写入集中返回我的 fd)。我也尝试了 poll() 设置了所有事件,再次没有区别。
  • 不要将你的 fd 推入 write fdsets。只有一个除外。
  • 试过了,管道没有运气。

标签: linux sockets pipe


【解决方案1】:
struct pollfd pfd = {.fd = yourfd, .events = POLLERR};
if (poll(&pfd, 1, whatever) < 0) abort();
if (pfd.revents & POLLERR) printf("pipe is broken\n");

这对我有用。请注意,套接字并不完全是管道,因此表现出不同的行为(-> 使用 POLLRDHUP)。

【讨论】:

  • 啊哈!我有一个错字,正在检查出路时的事件而不是rev​​ents。非常感谢,效果很好。
  • 很好的答案。我太习惯于 select() 调用。我必须明确地尝试在这一点上进化。 +1
【解决方案2】:

尝试使用 select 及其 errorfds 参数:

int **select**(int nfds, fd_set *restrict readfds,
      fd_set *restrict writefds, **fd_set *restrict errorfds**,
      struct timeval *restrict timeout);

【讨论】:

  • 谢谢,但我尝试将我的 fd 添加到异常集中,但在管道损坏时无法让它表现不同。 (它可能适用于套接字;我还没有尝试过,因为我当前的设置给了我一个管道)
【解决方案3】:

不错的答案,我喜欢它们...我还需要摆脱选择习惯并进入(e)投票。

这里有一些更传统的方法,如果你需要的话:

/* check whether a file-descriptor is valid */
int fd_valid(int fd)
{   
    if (fcntl(fd, F_GETFL) == -1 && errno == EBADF) return FALSE;
    return TRUE;
}       

这个尝试复制socket/fd。它比看起来简单得多,我留下了很多调试。

/* check a file descriptor */
int fd_check(int i) {
    int fd_dup = dup(i);
    if (fd_dup == -1) {
        strcpy(errst, strerror(errno));
        // EBADF  oldfd isn’t an open file descriptor, or newfd is out of the allowed range for file descriptors.
        // EBUSY  (Linux only) This may be returned by dup2() during a race condition with open(2) and dup().
        // EINTR  The dup2() call was interrupted by a signal; see signal(7).
        // EMFILE The process already has the maximum number of file descriptors open and tried to open a new one.

        if (errno == EBADF) {
            return FALSE;
        }   

        return TRUE;
    }   
    close(fd_dup);
    return TRUE;
}   

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 2022-01-25
    • 1970-01-01
    相关资源
    最近更新 更多