#c
Вопрос:
Ниже я добавляю сокеты в epoll и устанавливаю внутри индекс контекста приложения epoll_event.data.u32
.
При получении пакетов recv()
требуется дескриптор файла сокета. Во всех примерах events[i].data.fd
используется.
Однако events[i].data.fd
и events[i].data.u32
находятся в союзе, так как же мне также получить доступ к индексу пользовательского контекста events[i].data.u32
? Похоже, что он перезаписан дескриптором файла сокета?
// 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, amp;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, amp;buffer[0], sizeof(buffer), flags);
// How do I access the user-context index I set when adding the socket to epoll?
}
}
Ответ №1:
Вы указываете epoll_ctl()
, для какого дескриптора сокета вы хотите прослушивать события, и предоставляете epoll_event
структуру для связи с этой операцией прослушивания.
Всякий epoll_wait()
раз, когда вы обнаруживаете зарегистрированное событие в сокете, оно возвращает вам только epoll_event
структуру, которую вы предоставили для этого события, точно так же, как вы ее предоставили. Он не сообщает вам, какой сокет вызвал событие.
Итак, если вы хотите обнаружить сокет, вам нужно либо:
- сохраните сам дескриптор сокета в
epoll_event
, но тогда вы не сможете использовать какие-либо другие пользовательские данные. - сохраните дескриптор сокета где-нибудь в другом месте (т. Е. в массиве, пуле объектов и т. Д.), А Затем поместите идентифицирующую информацию, необходимую для возврата к дескриптору сокета, в виде пользовательских данных
epoll_event
(т. Е. индекс массива, указатель объекта и т. Д.).
Что бы вы ни вложили в epoll_event
«когда звоните epoll_ctl()
«, это то, от чего вы получите ответ epoll_wait()
. Ни больше, ни меньше.
Ответ №2:
Дизайн epoll удивительно прост. Роль epoll_data_t
состоит в том, чтобы обеспечить легкое сопоставление, а не хранение. Обратите внимание, что в нем есть void* ptr
элемент, который позволяет вам сопоставлять fd
(передавать epoll_ctl
) с чем угодно.
В вашем конкретном случае вы могли бы выделить a struct Context { int fd; uint32_t index; /*...*/ };
в куче и указать на эту структуру EPOLL_CTL_ADD
. Вам также придется освободить его после вызова EPOLL_CTL_DEL
каким-либо объектом (например, контейнером), которому принадлежит этот контекст.
Поскольку вы используете C , вы можете сохранить указатель на абстрактный EventListener
базовый класс, reinterpret_cast
начиная с void*
epoll_wait
этого класса, и отправить событие произвольному производному обработчику.