libevent 客户端使用IOCP发起多个连接会被服务器拒绝

时间:2022-09-16 00:14:09
我在使用lievent+IOCP的时候遇到一个测试问题。
测试环境:Windows XP,服务器使用IOCP

客户端创建1000个bufferevent,连接服务器同一个端口,不开启IOCP连接正常,开启IOCP之后,有一部分连接会被服务器主动拒绝。

不知道为什么会出现后面这种测试结果?

6 个解决方案

#1


引用 楼主 xujiezhige 的回复:
我在使用lievent+IOCP的时候遇到一个测试问题。
测试环境:Windows XP,服务器使用IOCP

客户端创建1000个bufferevent,连接服务器同一个端口,不开启IOCP连接正常,开启IOCP之后,有一部分连接会被服务器主动拒绝。

不知道为什么会出现后面这种测试结果?

IOCP的流程是服务器端先投递,后接收,
如果是采用AcceptEx,那可能是AcceptEx投递数量不足;
如果采用Accept,那就要查服务器端的读投递处理
----
没有看到具体的处理,仅供参考

#2



int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;

ProtoX::CProtoX oProtoX;
oProtoX.Init();
std::vector< ProtoX::CChannel* > vctChannel;
const int NUM_CHANNEL = 1000;
for( int i = 0; i < NUM_CHANNEL; ++i )
{
ProtoX::CChannel* pChannel = new ProtoX::CChannel( 
oProtoX.GetEventBase(), 
"127.0.0.1", 
ProtoX::SERVER_PORT );

PXASSERT( pChannel );
pChannel->SetDisconnectionCallback( 
google::protobuf::NewPermanentCallback( OnDisconnection, &oProtoX ) );
pChannel->SetErrorCallback( 
google::protobuf::NewPermanentCallback( OnError, &oProtoX ) );
vctChannel.push_back( pChannel );

ProtoX::EchoRequest oEchoRequest;
oEchoRequest.set_payload( "Hello Server" );
ProtoX::EchoService_Stub oEchoService( pChannel );
oEchoService.Echo( NULL, &oEchoRequest, NULL, NULL );

ProtoX::PtcC2SReq_ChatMessage oProtocol;
oProtocol.m_oReqChatMessage.set_type( ProtoX::ReqChatMessage::E_CHAT_TYPE_NEARBY );
oProtocol.m_oReqChatMessage.set_message( "I Send you a PtcC2SReq_ChatMessage" );
pChannel->SendProtocol( &oProtocol );
}

int iResult = oProtoX.Run();

for( int i = 0; i < NUM_CHANNEL; ++i )
{
delete vctChannel[ i ];
}

oProtoX.Uninit();
google::protobuf::ShutdownProtobufLibrary();
return iResult;
}


这是客户端的main函数,我把bufferevent封装成了CChannel,event_base封装到了CProtoX。通过编译宏MULTI_THREAD控制是否编译多线程版本(Windows平台下表明开启IOCP),当前我项目工程是添加了MULTI_THREAD的宏的。

创建1000个bufferevent,然后连接服务器,服务器也是开启IOCP的。

#3


客户端连接不上,不见得就是客户端的问题,Server端是如何处理的呢?

#4


引用 3 楼 xian_wwq 的回复:
客户端连接不上,不见得就是客户端的问题,Server端是如何处理的呢?


int main(int argc, char* argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;

ProtoX::CProtoX oProtoX;
oProtoX.Init();
ProtoX::CServer oServer( oProtoX.GetEventBase(), ProtoX::SERVER_PORT );

int iResult = oProtoX.Run();
oProtoX.Uninit();

google::protobuf::ShutdownProtobufLibrary();
return iResult;
}


ProtoX::CServer::CServer( event_base* pBase, ev_uint16_t wProt ) : 
m_pListener( NULL )
{
sockaddr_in oSockAddr = { 0 };
oSockAddr.sin_family = AF_INET;
oSockAddr.sin_port = INADDR_ANY;
oSockAddr.sin_port = htons( wProt );

m_pListener = evconnlistener_new_bind( 
pBase, 
OnNewConnection, 
this, 
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 
SOMAXCONN, 
( const sockaddr* )&oSockAddr, 
sizeof( oSockAddr ) );
PXASSERT( m_pListener );


evconnlistener_set_error_cb( m_pListener, OnListenerError );

}


服务器端是比较一般开启IOCP,监听端口。你那边有做过这个测试吗?如果你那边是好的,我可以对照一下

#5


通过查看 Libevent 源码,发现启动 IOCP 时,底层调用 ConnectEx API 进行连接。
查阅 MSDN 关于此函数的手册,发现一段话

If the error code returned is WSAECONNREFUSED, WSAENETUNREACH, or WSAETIMEDOUT, the application can call ConnectEx, WSAConnect, or connect again on the same socket

个人感觉,MS 认为调用此函数,最后完成端口返回 WSAECONNREFUSED 是一种正常行为,调用者可再次调用该 API 进行重连。

#6


请教一下,你那边开启iocp是用的那个EVENT_BASE_FLAG_STARTUP_IOCP吗?为什么我设置了这个,就接受不到客户端的连接请求 ?

#1


引用 楼主 xujiezhige 的回复:
我在使用lievent+IOCP的时候遇到一个测试问题。
测试环境:Windows XP,服务器使用IOCP

客户端创建1000个bufferevent,连接服务器同一个端口,不开启IOCP连接正常,开启IOCP之后,有一部分连接会被服务器主动拒绝。

不知道为什么会出现后面这种测试结果?

IOCP的流程是服务器端先投递,后接收,
如果是采用AcceptEx,那可能是AcceptEx投递数量不足;
如果采用Accept,那就要查服务器端的读投递处理
----
没有看到具体的处理,仅供参考

#2



int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;

ProtoX::CProtoX oProtoX;
oProtoX.Init();
std::vector< ProtoX::CChannel* > vctChannel;
const int NUM_CHANNEL = 1000;
for( int i = 0; i < NUM_CHANNEL; ++i )
{
ProtoX::CChannel* pChannel = new ProtoX::CChannel( 
oProtoX.GetEventBase(), 
"127.0.0.1", 
ProtoX::SERVER_PORT );

PXASSERT( pChannel );
pChannel->SetDisconnectionCallback( 
google::protobuf::NewPermanentCallback( OnDisconnection, &oProtoX ) );
pChannel->SetErrorCallback( 
google::protobuf::NewPermanentCallback( OnError, &oProtoX ) );
vctChannel.push_back( pChannel );

ProtoX::EchoRequest oEchoRequest;
oEchoRequest.set_payload( "Hello Server" );
ProtoX::EchoService_Stub oEchoService( pChannel );
oEchoService.Echo( NULL, &oEchoRequest, NULL, NULL );

ProtoX::PtcC2SReq_ChatMessage oProtocol;
oProtocol.m_oReqChatMessage.set_type( ProtoX::ReqChatMessage::E_CHAT_TYPE_NEARBY );
oProtocol.m_oReqChatMessage.set_message( "I Send you a PtcC2SReq_ChatMessage" );
pChannel->SendProtocol( &oProtocol );
}

int iResult = oProtoX.Run();

for( int i = 0; i < NUM_CHANNEL; ++i )
{
delete vctChannel[ i ];
}

oProtoX.Uninit();
google::protobuf::ShutdownProtobufLibrary();
return iResult;
}


这是客户端的main函数,我把bufferevent封装成了CChannel,event_base封装到了CProtoX。通过编译宏MULTI_THREAD控制是否编译多线程版本(Windows平台下表明开启IOCP),当前我项目工程是添加了MULTI_THREAD的宏的。

创建1000个bufferevent,然后连接服务器,服务器也是开启IOCP的。

#3


客户端连接不上,不见得就是客户端的问题,Server端是如何处理的呢?

#4


引用 3 楼 xian_wwq 的回复:
客户端连接不上,不见得就是客户端的问题,Server端是如何处理的呢?


int main(int argc, char* argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;

ProtoX::CProtoX oProtoX;
oProtoX.Init();
ProtoX::CServer oServer( oProtoX.GetEventBase(), ProtoX::SERVER_PORT );

int iResult = oProtoX.Run();
oProtoX.Uninit();

google::protobuf::ShutdownProtobufLibrary();
return iResult;
}


ProtoX::CServer::CServer( event_base* pBase, ev_uint16_t wProt ) : 
m_pListener( NULL )
{
sockaddr_in oSockAddr = { 0 };
oSockAddr.sin_family = AF_INET;
oSockAddr.sin_port = INADDR_ANY;
oSockAddr.sin_port = htons( wProt );

m_pListener = evconnlistener_new_bind( 
pBase, 
OnNewConnection, 
this, 
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 
SOMAXCONN, 
( const sockaddr* )&oSockAddr, 
sizeof( oSockAddr ) );
PXASSERT( m_pListener );


evconnlistener_set_error_cb( m_pListener, OnListenerError );

}


服务器端是比较一般开启IOCP,监听端口。你那边有做过这个测试吗?如果你那边是好的,我可以对照一下

#5


通过查看 Libevent 源码,发现启动 IOCP 时,底层调用 ConnectEx API 进行连接。
查阅 MSDN 关于此函数的手册,发现一段话

If the error code returned is WSAECONNREFUSED, WSAENETUNREACH, or WSAETIMEDOUT, the application can call ConnectEx, WSAConnect, or connect again on the same socket

个人感觉,MS 认为调用此函数,最后完成端口返回 WSAECONNREFUSED 是一种正常行为,调用者可再次调用该 API 进行重连。

#6


请教一下,你那边开启iocp是用的那个EVENT_BASE_FLAG_STARTUP_IOCP吗?为什么我设置了这个,就接受不到客户端的连接请求 ?