C++中的文件描述符

C++中的文件描述符,c++,C++,我正在写一个库,它将通过多种途径传输数据;TCP、UDP、RDMA远程直接内存访问,有时通过直接函数调用,其中客户机/服务器被合并为单个二进制文件 我将使用文件描述符处理TCP、UDP和RDMA,并一直在研究如何使用FunctionCallSocket类实现类似的功能,该类将采用大致的形式: class FunctionCallSocket { public: FunctionCallSocket(); ~FunctionCallSocket();

我正在写一个库,它将通过多种途径传输数据;TCP、UDP、RDMA远程直接内存访问,有时通过直接函数调用,其中客户机/服务器被合并为单个二进制文件

我将使用文件描述符处理TCP、UDP和RDMA,并一直在研究如何使用FunctionCallSocket类实现类似的功能,该类将采用大致的形式:

class FunctionCallSocket
{
    public:
        FunctionCallSocket();
        ~FunctionCallSocket();

        void send(char* buf, std::size_t len);
        void recv(char* dest, std::size_t len);

    private:
        char*  m_outboundBuffer;
        char*  m_inboundBuffer;
};
我想做的是能够像对待文件描述符一样对待这个类,这样我就可以将它与TCP、UDP等文件句柄一起传递给select/epoll

据我所知,文件描述符的整数值是由操作系统从一个私有表生成的,该表将文件映射到id,因此我需要对其进行欺骗


关于如何实现这一点,您有什么想法吗?

如果愿意,您可以使用特定于操作系统的调用来获取文件描述符。例如,unixopen函数将执行您想要的操作


或者,您可以将用于读取和写入数据的代码作为多态类层次结构的一部分,这将允许您在适当的情况下使用文件描述符和流库,例如用于文件I/O。事实上,一个想法可能是编写自定义流类来包装TCP连接,然后使用ostream和istream作为连接细节的包装。

如果它不是文件描述符,那么将其传递给select没有意义。如果在下面的某个地方有一个文件描述符,那么您要么需要一个API来公开它,要么需要一个低级API来将文件描述符添加到选择集中,并使类负责注册它使用的任何文件描述符。请注意,您已经熟悉了异步事件处理和回调领域。

如果您在Linux上运行,我建议您查看eventfd-这正是您想要的

在EFD_信号量模式下打开fd,您可以使用它跟踪有多少排队事件


每次写调用都会增加内核使用eventfd存储的计数器,每次读取都会减少计数器

使用此库的客户端将使用自己的线程从文件句柄中释放计数器。它们也将从该库的单独文件句柄中分离出来。我想通过使用select/epoll来统一调度过程。这并不像听起来那么容易。如果在下面的某个地方有一个文件描述符,并且语义是相同的,那么就可以不做重大更改,但是根据我的经验,这种情况很少发生。例如,Linux USB子系统使用文件描述符,但URB的完成是由FD变为可写的信号表示的,因此最终会出现许多特殊情况。我实际上不会通过文件描述符发送数据,而是通过FunctionCallObject拥有的指针上的函数调用发送数据。我只需要保留一个fd,这样它就不会被分配给其他对象,然后当数据到达FunctionCallSocket中的char*缓冲区时,以某种方式更改fd上的标志。虽然我完全不建议这样做,但您可以打开一个匿名管道或套接字,这会给您两个文件描述符;写入其中一个会使另一个可读,直到您从中读出数据为止。@Simon:可以用一个套接字来实现这一点,例如,本地绑定的UDP套接字连接到它自己。很有趣。调用open肯定会为我保留一个唯一的文件描述符。我实际上不会通过文件描述符发送数据,而是通过FunctionCallObject拥有的指针上的函数调用发送数据。当数据到达inboundBuffer/outboundBuffer时,是否有方法更改fd,以便选择/epoll查看数据?单独回答中的注释:使用此库的客户端将使用自己的线程从文件句柄中分离。它们也将从该库的单独文件句柄中分离出来。我想通过使用select/epoll来统一调度过程。