简体   繁体   English

调用epoll_wait时如何访问epoll上的用户上下文数据集

[英]How to access user-context data set on epoll when calling epoll_wait

Below I add sockets to epoll and set an application-context index within epoll_event.data.u32 .下面我将套接字添加到 epoll 并在epoll_event.data.u32设置应用程序上下文索引。

When receiving packets, recv() requires the socket file descriptor.接收数据包时, recv()需要套接字文件描述符。 In all the examples events[i].data.fd is used.在所有示例中都使用了events[i].data.fd

However, events[i].data.fd and events[i].data.u32 are in a union, so how do I also access my user-context index events[i].data.u32 ?但是, events[i].data.fdevents[i].data.u32是联合的,那么我如何访问我的用户上下文索引events[i].data.u32 It looks like it is overwritten with the socket file descriptor?看起来它被套接字文件描述符覆盖了?

// Initially
int epollFd = epoll_create1(0);

// Adding each socket, along with a user-context index for callbacks
struct epoll_event event;
event.events = EPOLLIN;
event.data.u32 = callbackIndex; // Here is the user-defined index
int sock = createSocket(port, address);
assert(epoll_ctl(epollFd, EPOLL_CTL_ADD, sock, &event));

// Later when receiving packets

struct epoll_event events[MAX_EVENTS];

while (true)
{
    int event_count = epoll_wait(epollFd, events, MAX_EVENTS, 30000);
            
    for (i = 0; i < event_count; i++)
    {
        int n = recv(events[i].data.fd, &buffer[0], sizeof(buffer), flags);
        // How do I access the user-context index I set when adding the socket to epoll?
    }
}

You tell epoll_ctl() which socket descriptor you want to listen for events for, and provide an epoll_event struct to associate with that listen operation.你告诉epoll_ctl()你想要监听哪个套接字描述符,并提供一个epoll_event结构来与监听操作相关联。

Whenever epoll_wait() detects a registered event on a socket, it gives you back only the epoll_event struct that you had provided for that event, exactly as you had provided it.每当epoll_wait()检测到套接字上的注册事件时,它只会返回您为该事件提供的epoll_event结构,与您提供的完全一样。 It does not tell you which socket triggered the event.不会告诉您哪个套接字触发了事件。

So, if you want to discover the socket, you have to either:因此,如果您想发现套接字,您必须:

  • store the socket descriptor itself in the epoll_event , but then you can't use any other user-defined data.将套接字描述符本身存储在epoll_event ,但是您不能使用任何其他用户定义的数据。

  • store the socket descriptor somewhere else (ie, in an array, an object pool, etc) and then put identifying information needed to get back to the socket descriptor as user-defined data in the epoll_event (ie, array index, object pointer, etc).将套接字描述符存储在其他地方(即,在数组、对象池等中),然后将返回套接字描述符所需的标识信息作为用户定义的数据放在epoll_event (即,数组索引、对象指针等) )。

Whatever you put in the epoll_event when calling epoll_ctl() is what you will get back from epoll_wait() .调用epoll_ctl()时在epoll_event放入的epoll_event都是从epoll_wait() No more, no less.不多也不少。

Design of epoll is beautifully simple. epoll 的设计非常简单。 The role of epoll_data_t is to provide lightweight mapping rather than storage . epoll_data_t的作用是提供轻量级映射而不是存储 Notice that it has a void* ptr member, which allows you to map from fd (passed to epoll_ctl ) to anything .请注意,它有一个void* ptr成员,它允许您从fd (传递给epoll_ctl )映射到任何东西

In your particular case, you could allocate a struct Context { int fd; uint32_t index; /*...*/ };在您的特定情况下,您可以分配一个struct Context { int fd; uint32_t index; /*...*/ }; struct Context { int fd; uint32_t index; /*...*/ }; on the heap and point to that structure on EPOLL_CTL_ADD .在堆上并指向EPOLL_CTL_ADD上的该结构。 You would have to also deallocate it after calling EPOLL_CTL_DEL by some object (eg container) which owns that context.在通过拥有该上下文的某个对象(例如容器)调用EPOLL_CTL_DEL之后,您还必须取消分配它。

Since you are using C++, you could store a pointer to an abstract EventListener base class, reinterpret_cast from void* after epoll_wait to that class and dispatch event to an arbitrary derived handler.由于您使用C ++,你可以存储指向一个抽象的EventListener基类reinterpret_castvoid*epoll_wait的那类和分派事件到任意来源的处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM