有没有办法获得套接字描述符,因为哪个select()调用返回EBADF?

时间:2016-05-02 11:06:54

标签: c++ c sockets

我有一个代码,我在其中使用select()函数调用来轮询添加到为任何传入数据设置的readfds的套接字列表。

while(1) {
    ret = select(n,&readfds,NULL,NULL,&tv);
    if(ret == -1) {
        perror("Select Failed");
    } else if (ret == 0){
        printf("Select Timeout\n");
    } else {
           recv(clientSocket, buffer, 1024, 0);
           printf("Data received: %s",buffer);
    }
}

我在readfds列表中添加了很多套接字。我的代码中有另一个线程正在关闭readfds列表中的套接字(从列表中删除套接字不是预期的行为)。因此,如果套接字在另一个线程中被删除,则上面的循环正在抛出"选择失败:错误的文件描述符"。

1)避免这种情况的一种方法是修复其他线程中的错误以阻止从列表中删除套接字

2)另一种方法是在select函数调用中获取给出错误的文件描述符错误的套接字并从readfds中提到的套接字列表中删除它(我可以在另一部分中再次将相同的套接字添加到列表中程序)。

我正在尝试第一个选项。虽然我也想知道,有没有办法获得套接字描述符,因为哪个select()调用返回EBADF?

2 个答案:

答案 0 :(得分:4)

  1. 由于fd_set数据结构的大小限制,选择不支持超过FD_SETSIZE描述符的数量。 FD_SETSIZE通常是1024。
  2. 您发布的代码使用Select的方式存在问题。由于select修改了传递的fd_sets,因此不能重复使用它们,每次准备Select调用时都需要更新fd_set和max fd编号。
  3. 选择不支持多线程使用,因为它不是这样设计的。根据男子选择:
  4.   

    多线程应用程序

         

    如果select()监视的文件描述符在另一个线程中关闭,          结果未指定。在某些UNIX系统上,select()取消阻止并返回,          指示文件描述符已准备就绪(后续I / O操作          除非另一个文件描述符重新打开,否则可能会失败并显示错误          返回时间select()和执行I / O操作之间的时间。上          Linux(以及其他一些系统),在另一个线程中关闭文件描述符          对select()没有影响。总之,任何依赖于参与者的应用程序          在这种情况下,ular行为必须被认为是错误的。

    1. 尝试使用更现代的epoll,并使用线程池进行备份。
    2. 有用的指南是http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/

答案 1 :(得分:1)

如果另一个线程正在关闭一个文件描述符,并且你想在主线程中使用相同的描述符(select()),理论上你有一个"竞争条件"。在任何给定时间在多个线程中使用相同的资源。

您应该保护filedescriptor引用,就像保护并发内存访问一样。 filedescriptor号码可以在下一次接受/连接/打开呼叫时重复使用,导致与您当前的方法不一致。