Здравствуйте, maks1180, Вы писали:
M>Задача стандартная — сетевое приложение, которое отвечает на входящие запросы. M>Нужно получать уведомления: M>1) EPOLLIN (на чтение) — если есть что прочитать из сокета (т.е. следим за состоянием). M>2) EPOLLOUT (на запись) — только при смене состояния (т.е. следим за изменением состояния) на возможность записи, т.е. если раньше нельзя было писать а теперь можно.
M>В Windows через оконные сообщения, как раз так и работает, как я описал. Но в Линуксе, кажется нет хорошего решения.
M>Вариант №1 вызываем epoll_ctl( EPOLLET + EPOLLIN+EPOLLOUT) M>не буду получать нотификацию EPOLLIN до следующих принятых данных, если прочитаю не всё что есть в сокете. M>Как понять, что я всё прочитал из сокета ?
чтение вернет данных меньше чем размер предоставленного под чтение буфера, либо чтение вернет ноль данных и диагностику EAGAIN (сокет неблокирующий)
M>Вариант №2 вызываем epoll_ctl( EPOLLIN+EPOLLOUT) — без EPOLLET M>буду постоянно получать EPOLLOUT, придёться постоянно вызывать epoll_ctl, что-бы снять или поставить EPOLLOUT. Это же функция ядра и вызов будет занимать время значительное ? M>Вроде libuv так делает.
M>Вариант №3 вызывать 2 раза epoll_ctl для одного и тогоже сокета. Так можно ? M>epoll_ctl(EPOLLIN) M>epoll_ctl(EPOLLOUT+EPOLLET)
M>Какие ещё есть решения ?
Сделать адаптер из ET в LT.
За базовый — берем ET. Для записи — используем его как есть.
Для чтения — заводим дополнительный булевый флажок со смыслом "есть что читать", по умолчанию сброшен, при получении EPOLLIN — взводим, при неблокирующем чтении — если вычитано меньше данных нежели предоставленный под чтение буфер или вычитано 0 и выдана диагностика EAGAIN — сбрасываем. Чтение, естественно, неблокирующее, чтобы вместо блока был EAGAIN. Вот и все, булевый флажок в основном эквивалентен предикату "есть что читать", остается лишь малый кейс при котором это не так — если при очередном чтении было вычитано данных ровно под размер буфера и именно такое количество данных и было доступно.. Но, это легко отрулить.