如何正确使用select()中的except_set?

时间:2013-04-27 01:14:56

标签: c sockets

我还没有找到示例代码。下面是我在一组套接字上测试的代码的一部分。请注意(不在下面的代码中),我将“except_set”设置为“read_set”和“write_set”的并集,以便监视所涉及的所有套接字。

基本上我希望看​​到的是当错误发生时,它应该打印出错误列表 - 一些套接字。但是,我观察的是“n == -1”的情况,它只给出一条错误消息(在我的例子中,“坏文件描述符”)。打印出遇到错误的套接字会更好。

另一个问题:由于只有一个“errno”,它如何表示多个套接字的错误(如果一个select()调用中有多个套接字遇到错误)。我真的很困惑。在每个插槽的基础上捕获“except_set”会出现什么样的错误?什么是正确的使用方式?非常感谢。

    int n = select(max_fd + 1, &(read_set), &(write_set), &(except_set), &tv);

    if (n == -1)
    {
        perror("select()");
        exit(1);
    }

    else if (n == 0)
    {
        // process time-out ...
    }

    else // (n > 0)
    {
        for (int i=0; i < max_fd; ++i)
        {
            if (FD_ISSET(i, &(read_set)))
            {
                // process read
            }

            if (FD_ISSET(i, &(write_set)))
            {
                // process write
            }

            if (FD_ISSET(i, &(except_set)))
            {
                printf("error, %s, socket= %d", strerror(errno), i);
            }
        }
    }

1 个答案:

答案 0 :(得分:2)

您正在检查的errno的值与具有异常条件的套接字无关。实际上它与select无关。它只是前一次调用的剩余部分,或者在非错误情况下进行虚假设置。在标准库函数中收到失败返回值(通常为errno-1)之后,唯一的NULL有意义。

至于什么特殊情况意味着:

  

如果套接字有未决错误,则应将其视为待处理的异常情况。否则,构成异常条件的是文件类型特定的。对于与套接字一起使用的文件描述符,它是协议特定的,除非如下所述。对于其他文件类型,它是实现定义的。如果操作对于特定文件类型没有意义,则pselect()或select()将指示描述符已准备好进行读取或写入操作,并应指示描述符没有待处理的异常条件。

     

...

     

如果对打开的文件描述清除了O_NONBLOCK并且设置了MSG_OOB标志的接收操作将返回带外数据而不阻塞,则应认为套接字具有异常条件。 (无论MSG_OOB标志是否用于读取带外数据,都是特定于协议的。)如果接收队列中存在带外数据标记,则套接字也应被视为具有异常条件。 。可以认为套接字具有待决异常条件的其他情况是协议特定的和实现定义的。

来源:http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html

如果套接字有错误状态,可以使用SO_ERROR的{​​{1}}选项获取。

通常,不需要使用getsockopt的例外集。如果套接字已关闭,它将显示为可读,并将为您提供文件结束(零长度读取)。然而,通常协议栈无法立即检测到连接丢失,因此您只会收到写入错误(可能select除非您禁止它)尝试写入套接字,此时系统确定它不能再写了。就个人而言,我从未找到过使用SIGPIPE的特殊集合的机会。