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 );
据我所知,这是从示例中复制和粘贴的,所以它应该可以工作。我的 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 );
它永远不会发送第一次。为了让它发送,我必须发送第二个充满数据的缓冲区。
这种行为让我很痛苦,我为此花费了很多时间。有什么想法吗?
//-------------------------------------------- ----------
我最终放弃了,改用了这个 hack……只是没有足够的信息告诉我为什么 libevent 没有写入套接字。这很好用。
int result = send( m_connectionId, (const char* )buffer, bufferOffset, 0 );
最佳答案
我也遇到了这个问题!我在这个问题上花了一天时间。最后,我解决了它。
当您调用event_base_dispatch
的线程时,它将处于休眠状态,直到任何信号量将其唤醒。所以,当它休眠时,你调用bufferevent_write
,bufferevent 的fd 添加到事件列表中,但它不会是epoll 直到下一次。所以你必须在调用bufferevent_write
后发送信号量来唤醒调度线程。您可以使用的方法是设置事件绑定(bind)对套接字并将其添加到 event_base
。然后在需要唤醒调度线程时随时发送 1 个字节。
关于c++ - Libevent 仅在第二次 buffer_write 之后写入套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15995659/