有没有办法将文件描述符与用户定义的数据相关联?

时间:2011-11-17 23:15:39

标签: c sockets posix

我正在编写一个客户端 - 服务器应用程序,它使用POSIX poll函数来提供一种并发客户端处理的形式。客户端还具有状态和其他相关数据,这些数据存储在客户端结构中。

我当前的问题是,当我从poll获得提示在与客户端关联的套接字文件描述符(概念上)上执行I / O时,我必须将文件描述符实际匹配到其关联的客户数据结构。目前我进行O(n_clients)查询(我的客户端数据结构存储描述符),但我想知道是否存在更好的替代方案?

4 个答案:

答案 0 :(得分:4)

没有。如果存在,则必须由内核跟踪,因此查找数据将涉及系统调用。系统调用的成本比在用户空间中进行O(n)查找要贵一个数量级。

您一次与多少客户打交道?除非数百或更多,否则与执行任何I / O的成本相比,查找的成本将微不足道。

您可以使用由文件描述符索引的数组,而不是使用O(n)查找,假设您不会同时打开超过一定数量的描述符。例如:

#define MY_MAX_FD 1024  // Tune this to your needs
void *per_fd_data[MY_MAX_FD];

void *get_per_fd_data(int fd)
{
    assert(fd >= 0);
    if(fd < MY_MAX_FD)
        return per_fd_data[fd];
    else
    {
        // Look up fd in a dynamic associative array (left as an exercise to the
        // reader)
    }
}

答案 1 :(得分:2)

最便宜的是制作一个固定大小的连接结构数组,每个条目都有{state,* context,...,也许是回调函数},用fd索引(= O(1 ))。内存很便宜,你可以负担几百或几千个文件描述符和表条目。

编辑:你不需要使其固定大小。如果您的民意调查结构或fdset是固定的:将其固定;否则使用getdtablesize()或getrlimit()来获取要分配的条目数。

答案 2 :(得分:1)

如果您使用poll()select()/pselect(),则应自行保留数据,例如在其他人提到的哈希表或数组中。这是最便携的解决方案。一些备用接口确实有关联您自己的用户数据的方法。例如,使用asynchronous I/O(例如aio_read()),您可以提供可在异步请求完成时传递给信号处理程序或线程的用户值sigev_value。 Linux epoll接口还允许为集合中的每个文件描述符指定用户数据。

答案 3 :(得分:1)

除了所有其他非常有用的答案之外,我想提供以下信息,希望它本着知识库的精神对其他人有用。

问题在于,如果我们假设符合POSIX的系统http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_14,它会指定以下内容(强调我的):

  

除非另有说明,否则打开一个或多个文件描述符的所有函数都应以原子方式分配最低编号的可用(即,在调用进程中尚未打开)文件描述符。分配。在单个函数分配两个文件描述符(例如,pipe()socketpair())的情况下,分配可以是独立的,因此应用程序不应期望它们具有相邻值或取决于具有较高值的​​值。

这允许程序简单地保留一个阵列,直到它想要支持的许多描述符,其中开放描述符可以仅用作数组下标来引用类似客户端连接的数据。基本上,这种系统上的开放文件描述符可以直接用作表格的索引,该表格实现为数组。毕竟,文件描述符号码不仅会从最低的availbale值向上增长,它们似乎也会被重用 - 如果你关闭描述符10,而你仍然有描述符11和向上打开,下次你打开一个描述符,一个POSIX-兼容系统将使用索引10打开描述。这也使得在fd-indexed表中重用行非常简单。