Я буду держать коротко. Как очистить данные, ожидающие в bufferevent
выходной буфер прямо в сокет блокирующим образом.
После закрытия моего класса оболочки сокета после выполнения асинхронной записи (используя evbuffer_add
), Либивент выплевывает epoll
ошибки, указывающие на то, что была предпринята попытка записи на недействительный fd. Мне нужно иметь возможность сбрасывать ожидающие данные libevent в сокет, какие-либо предложения?
Примечание: специфическая ошибка: Epoll MOD (4) на fd 9 не удалось. Старые события были 6; изменение чтения было 2 (del); изменение записи было 0 (нет): неверный дескриптор файла.
Вы пытались отключить задержку сокета? Отключение задержки сокета заставляет сокет не ждать неотправленных данных перед закрытием сокета.
struct linger linger;
memset(&linger, 0, sizeof(struct linger));
retVal = setsockopt(sock, SOL_SOCKET, SO_LINGER, (const void*)&linger, sizeof(struct linger));
Для любого из тех, кто может столкнуться с той же ошибкой, я обнаружил, в чем заключается моя проблема — спасибо Инге Хенриксен.
class ASocket
{
// ...
~ASocket()
{
if(m_handle.bev)
{
bufferevent_free(m_handle.bev);
}
if(m_handle.fd >= 0)
::close(m_handle.fd);
}
// ...
}
После удаления асинхронного объекта сокета (ASocket
), bufferevent
будет освобожден, если он существует, и сокет будет удален — libevent продолжит работать на закрытом сокете. Обратите внимание, что bufferevent_free, как указано в http://www.wangafu.net/~nickm/libevent-book/Ref6_bufferevent.html#_freeing_a_bufferevent, но не на странице документации Doxygen, не освободит bufferevent
по вызову bufferevent_free
функция, а скорее:
Однако функция bufferevent_free () пытается освободить буфер как можно скорее.
Это было исправлено так:
class ASocket
{
// ...
// If bufferevent exists, it must be created with
// the BEV_OPT_CLOSE_ON_FREE flag.
~ASocket()
{
if(m_handle.bev)
{
bufferevent_free(m_handle.bev);
}
else
{
if(m_handle.fd >= 0)
::close(m_handle.fd);
}
}
// ...
}
Если розетка имеет bufferevent
, он освобождается и libevent закроет сокет, как только он будет завершен.
Я не мог сделать это внутри самого обратного вызова, но это можно сделать с помощью другого обратного вызова, см. https://github.com/libevent/libevent/blob/master/sample/le-proxy.c
if (partner) {
/* Flush all pending data */
readcb(bev, ctx);
if (evbuffer_get_length(
bufferevent_get_output(partner))) {
/* We still have to flush data from the other
* side, but when that's done, close the other
* side. */
bufferevent_setcb(partner,
NULL, close_on_finished_writecb,
eventcb, NULL);
bufferevent_disable(partner, EV_READ);
} else {
/* We have nothing left to say to the other
* side; close it. */
bufferevent_free(partner);
}
}