c++ - 如果数据已经发送,为什么 select 只将文件描述符显示为就绪?

标签 c++ c linux network-programming synchronous

我在线程中使用 select() 来监视数据报套接字,但除非在线程启动之前将数据发送到套接字,否则 select() 将继续返回 0。

我混合了一点 C 和 C++;这是启动线程的方法:

bool RelayStart() {
    sock_recv = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&addr_recv, 0, sizeof(addr_recv));
    addr_recv.sin_family = AF_INET;
    addr_recv.sin_port = htons(18902);
    addr_recv.sin_addr.s_addr = htonl(INADDR_ANY);
    bind(sock_recv, (struct sockaddr*) &addr_recv, sizeof(addr_recv));

    isRelayingPackets = true;

    NSS::Thread::start(VIDEO_SEND_THREAD_ID);

    return true;
}

停止线程的方法:

bool RelayStop() {
    isSendingVideo = false;
    NSS::Thread::stop();
    close(sock_recv);
    return true;
}

并且方法在线程中运行:

void Run() {

    fd_set read_fds;
    int select_return;
    struct timeval select_timeout;

    FD_ZERO(&read_fds);
    FD_SET(sock_recv, &read_fds);

    while (isRelayingPackets) {

        select_timeout.tv_sec = 1;
        select_timeout.tv_usec = 0;

        select_return = select(sock_recv + 1, &read_fds, NULL, NULL, &select_timeout);
        if (select_return > 0 && FD_ISSET(sock_recv, &read_fds)) {
            // ...
        }
    }
}

问题是,如果在调用 RelayStart() 之前没有进程已经将 UDP 数据包发送到端口 18902,则 select() 将始终返回 0。因此,例如,我无法在不重新启动的情况下重新启动发送方线程(以正确的顺序。)

只要首先启动发送方,一切似乎都可以正常工作。

最佳答案

Run 线程只构造一次read_fds

select 调用更新 read_fds 以清除所有未准备好数据的描述符的所有位,并为之前和之前设置的描述符设置所有位准备好数据。

因此,如果没有描述符准备好任何数据并且 select 调用超时(并返回 0),则现在清除 read_fds 中的所有位。传递相同的全零位掩码的进一步调用将不会扫描任何文件描述符。

您可以在循环内的每次行程中重新构建读取集:

while (isRelayingPackets) {
    FD_ZERO(&read_fds);
    FD_SET(sock_recv, &read_fds);
    ...
}

或者使用带有位集拷贝的辅助变量:

while (isRelayingPackets) {
    fd_set select_arg = read_fds;
    ... same as before but use &select_arg ...
}

(或者,当然,还有非select接口(interface)在某些方面更容易使用。)

关于c++ - 如果数据已经发送,为什么 select 只将文件描述符显示为就绪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10254397/

相关文章:

c++ - 列计数和列 decltypes 在 SQLite 预准备语句执行期间是否不变?

c - ld : symbol(s) not found for architecture x86_64 error message when compiling

linux - 从我之前离开的地方拖尾文件?

java - 在 Windows、C++ 和 Java 中加密传输中的数据

c++ - 使用继承时,带有 CRTP 的 typedef 不起作用

c++ - 将自定义矩阵转换为 float *

c - GNU C 内联 asm "m"约束与指针 : address vs. 指向的值?

linux - 比较两个不同文件的内容

regex - ngrep 如何使匹配表达式不区分大小写?

使用预处理器指令生成 C++ 类