Libevent пишет в сокет только после второго buffer_write

Libevent великолепен, и я люблю его до сих пор. Однако на эхо-сервере запись только отправляется в сокет при второй записи. Я пишу из другого потока, потока насоса, который общается с БД и выполняет минимальное массирование данных.

Я подтвердил это, настроив обратный вызов для записи:

bufferevent_setcb( GetBufferEvent(), DataAvailable, DataWritten, HandleSocketError, this );

вызов bufferevent_flush (m_bufferEvent, EV_READ | EV_WRITE, BEV_NORMAL), похоже, не имеет никакого эффекта.

Вот настройка, на случай, если я ее где-нибудь взорвал. Я значительно упростил накладные расходы в моей кодовой базе, чтобы получить некоторую помощь. Это включает в себя инициализацию сокетов, инициализацию моего потока и т. Д. Это многопоточное приложение, поэтому там могут быть некоторые проблемы. Я начну с этого:

m_LibEventInstance = event_base_new();
evthread_use_windows_threads();
m_listener = evconnlistener_new_bind( m_LibEventInstance,
OnAccept,
this,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE,
-1,// no maximum number of backlog connections
(struct sockaddr*)&ListenAddress, socketSize );

if (!m_listener) {
perror("Couldn't create listener");
return false;
}
evconnlistener_set_error_cb( m_listener, OnSystemError );

AFAIK, это копирование и вставка из образцов, поэтому оно должно работать. Мой OnAccept делает следующее:

void  OnAccept( evconnlistener* listenerObj, evutil_socket_t newConnectionId, sockaddr* ClientAddr, int socklen, void* context )
{
// We got a new connection! Set up a bufferevent for it.
struct event_base*  base = evconnlistener_get_base( listenerObj );
struct bufferevent* bufferEvent = bufferevent_socket_new( base, newConnectionId, BEV_OPT_CLOSE_ON_FREE );

bufferevent_setcb( GetBufferEvent(), DataAvailable, DataWritten,
HandleSocketError, this );

// We have to enable it before our callbacks will be called.
bufferevent_enable( GetBufferEvent(), EV_READ | EV_WRITE );

DisableNagle( m_connectionId );
}

Теперь я просто отвечаю на поступающие данные и сохраняю их в буфере для последующей обработки. Это многопоточное приложение, поэтому я буду обрабатывать данные позже, обрабатывать их или возвращать ответ клиенту.

void     DataAvailable( struct bufferevent* bufferEventObj, void* arg )
{
const U32   MaxBufferSize = 8192;
MyObj*   This = (MyObj*) arg;
U8          data[ MaxBufferSize ];
size_t      numBytesreceived;

/* Read 8k at a time and send it to all connected clients. */
while( 1 )
{
numBytesreceived = bufferevent_read( bufferEventObj, data, sizeof( data ) );
if( numBytesreceived <= 0 ) // nothing to send
{
break;
}

if( This )
{
This->OnDataReceived( data, numBytesreceived );
}
}
}

последнее, что происходит, когда я просматриваю свои данные, упаковываю их в буфер и затем делаю это на поточном временном интервале:

bufferevent_write( m_bufferEvent, buffer, bufferOffset );

Это никогда, никогда не отправляет в первый раз. Чтобы заставить его отправлять, я должен отправить второй буфер, полный данных.

Такое поведение убивает меня, и я потратил на это много часов. Есть идеи?

// ———————————————— ——-

Я наконец сдался и использовал этот взлом вместо этого … просто не было достаточно информации, чтобы сказать мне, почему libevent не записывал в сокет. Это работает просто отлично.

int result = send( m_connectionId, (const char* )buffer, bufferOffset, 0 );

2

Решение

Я тоже столкнулся с проблемой! Я потратил один день на эту проблему. Наконец-то я это решил.

Когда нить вы звоните event_base_dispatchОн будет спать до тех пор, пока его не разбудит семафор. Итак, когда он спит, вы звоните bufferevent_write, fd bufferevent добавляет в список событий, но это не будет epoll до следующего раза. Поэтому вы должны отправить семафор, чтобы разбудить поток рассылки после того, как вы позвонили bufferevent_write, Вы можете использовать способ установки сокета пары привязки событий и добавления его в event_base, Затем отправьте 1 байт в любое время, когда вам нужно разбудить поток рассылки.

-1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]