epoll 并发接收数据丢失问题
我在windows上通过批处理快速的循环打开了10多个客户端, 客户端一启动马上就向服务器发送数据,通过观察,发现客户端并发的一起向服务器发送数据频率是0.1秒, 大概22字节的样子, 总是有1~2个客户端发送的数据服务器没有收到(receiveSocketData接口就没有被触发)。
注意:我的测试模式是 服务器收到包则会返回一个包, 客户端也是收到一个包才会发送一个包, 因此那2个客户端是第一次发送服务器就没收到而后就不能继续发往服务器了, 他们的连接是通的。
服务器大概这个样子:
startEpoll()
{
socklen_t socklen;
int n = 0;
if ( !isInit() ){
DEBUG_MSG( ">>you must to init epoll.\n" );
return -1;
}
if ( listen( listener, lisnum ) == -1 )
{
perror( ">>listen" );
return -1;
}
else
DEBUG_MSG( ">>start server of network is successfully!\n" );
/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
kdpfd = epoll_create( m_maxEpollSize );
socklen = sizeof( struct sockaddr_in );
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listener;
if ( epoll_ctl( kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0 )
{
fprintf( stderr, ">>epoll set insertion error: fd=%d\n", listener );
return -1;
}
else
DEBUG_MSG( ">>listen socket add epoll successfully!\n");
curfds = 1;
m_isRun = true;
while ( m_isRun ) {
//pthread_testcancel();//设置线程取消点
/* 等待有事件发生 -1表示一直等待 */
nfds = epoll_wait( kdpfd, events, curfds, -1 );
if ( nfds == -1 ) {
perror( ">>epoll_wait" );
return -1;
}
/* 处理所有事件 */
for ( n = 0; n < nfds; ++n ) {
if ( events[ n ].data.fd == listener ) //是主socket的事件发生
{
struct sockaddr_in their_addr;
int new_fd = accept( listener, (struct sockaddr *) &their_addr, &socklen );
//if ( errno == EAGAIN )
// return 0 ;
if ( new_fd < 0 ) {
perror( ">>accept is error! new_fd = 0." );
continue;
}
// 客户端连接通知
if ( 0 != validNewSocket( their_addr ) ){
close( new_fd );
DEBUG_MSG( ">>close a illegal the client, address: %s", inet_ntoa( their_addr.sin_addr ) );
continue;
}
// 把socket设置为非阻塞方式
setnonblocking( new_fd );
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = new_fd;
if ( epoll_ctl( kdpfd, EPOLL_CTL_ADD, new_fd, &ev ) < 0 ) {
fprintf( stderr, ">>to socket '%d' add epoll failed!%s\n", new_fd, strerror( errno ) );
return -1;
}
curfds++;
SocketBufferAssigner::getSingleton().assignSocketBuffer( new_fd );
App::getSingleton().onNewSocketAdd( new_fd, inet_ntoa( their_addr.sin_addr ), ntohs( their_addr.sin_port ) );
DEBUG_MSG( ">>connect from: %s : %d, created socket: %d, currCount : %d\n", inet_ntoa( their_addr.sin_addr ), ntohs( their_addr.sin_port ), new_fd, curfds );
}
else
{
// 接受客户端的数据
int nRet = receiveSocketData( events[ n ].data.fd );
if ( nRet < 1 && errno != 11 )
{
printf( "fdsafsadfdsafsdafdsafsadfsadfasd\n");
curfds--;
epoll_ctl( kdpfd, EPOLL_CTL_DEL, events[ n ].data.fd, &ev);
SocketBufferAssigner::getSingleton().detachSocketBuffer( events[ n ].data.fd );
App::getSingleton().onSocketLeave( events[ n ].data.fd );
}
}
}
}
return 0;
}
// 包接收处理
receiveSocketData( int socketID )
{
char buf[ EPOLL_MAXBUF + 1 ];
bzero( buf, EPOLL_MAXBUF + 1 );
/* 开始处理每个新连接上的数据收发 */
/* 接收客户端的消息 */
int recvlen = recv( socketID, buf, sizeof( buf ), 0 );
if( recvlen < 0 )
{
// 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读
// 在这里就当作是该次事件已处理处.
if(errno == EAGAIN){
DEBUG_MSG( ">>socket %d ==EAGAIN!\n", socketID );
return 1;
}
else
{
DEBUG_MSG( ">>receive data is failed! error code:%d, errstr:'%s', currCount : %d\n", errno, strerror( errno ), curfds );
return -1;
}
}
else if( recvlen == 0 )
{
// 这里表示对端的socket已正常关闭.
DEBUG_MSG( ">>socket %d exit! currCount : %d\n", socketID, curfds );
close( socketID );
return 0;
}
else if ( recvlen == 1 && buf[0] == '0' ){
close( socketID );
close( listener );
exit( 1 );
}
else if( recvlen == sizeof( buf ) )
{
// 需要再次读取
printf("WARNING-----%d, %d\n",recvlen,strlen( (char*)&buf ));
return 1;
}
else
{
static std::vector<int> tmppp;
std::vector<int>::iterator ite = std::find( tmppp.begin(), tmppp.end(), socketID );
if ( ite == tmppp.end() ){
printf("-----------%s, %d\n",buf,socketID);
tmppp.push_back( socketID );
}
//KBPerf* kbp = new KBPerf( "push-socketData" );
//kbp->collect();
// 将所有接收到的消息全部压入环形缓冲区
SocketBufferAssigner::getSingleton().getSocketRecvBuffer( socketID )->push( (char*)&buf, recvlen );
//kbp->getExecInterval();
}
/* 处理每个新连接上的数据收发结束 */
return recvlen;
}