本文要说的是游戏服务器之逻辑网关,在单进程的逻辑服务器中存在多个逻辑网关。
设计上:
(1)逻辑网关个数是配置的
(2)每个逻辑网关就包含四类线程:
1)网关接收连接线程:循环检查连接并建立新会话
2)网关的数据发送线程(配置多个):发送消息发送队列的数据,每个发送线程处理该线程的,多线程发送
3)网关的数据接收线程:网络接收数据到数据包接收队列
4)网关的数据处理线程: 处理连包,校验,派送到账号线程(登录消息)或逻辑线程(系统消息)
1、网关接收连接线程
接收连接和创建会话
网关接收连接循环不断地检查新连接的接收
void *CSelectRunSockProcesser::AcceptThreadRoutine(CSelectRunSockProcesser *pRunSock)
{
while ( !pRunSock->m_boStoping )
{
pRunSock->NewSession();
}
ExitThread( 0 );
}
检查建立新的会话(这里是select模型检查)
VOID ExecSockMgr::NewSession()
{
SOCKET nSocket;
SOCKADDRIN sRemote;
int nErr;
socklen_t nRemoteSize;
u_long uBlock;
PRUNGATEUSERSESSION pSession;
fd_set readfds, errfds;
timeval tv;
FD_ZERO( &readfds );
FD_ZERO( &errfds );
FD_SET( m_ListenSocket, &readfds );
tv.tv_sec = 1;
tv.tv_usec = 0;
//检查是否有接入的socket
nErr = select( int(m_ListenSocket+1), &readfds, NULL, &errfds, &tv );
if ( nErr < 0 || FD_ISSET(m_ListenSocket, &errfds) )
{
SocklogError( __FUNCTION__, "select", WSAGetLastError() );
return;
}
if ( nErr == 0 || !FD_ISSET(m_ListenSocket, &readfds) )
{
return;
}
if ( m_boStoping )
{
return;
}
nRemoteSize = sizeof(sRemote);
nSocket = accept( m_ListenSocket, (sockaddr*)&sRemote, &nRemoteSize );
if ( nSocket == INVALID_SOCKET )
{
SocklogError( __FUNCTION__, "accept", WSAGetLastError() );
return;
}
//用户队列满后一段时间内不接受新连接
if ( GetTickCount() < m_SessionFullTick )
{
closesocket( nSocket );
return;
}
uBlock = 1;
//设置非阻塞
int nFlag = fcntl(nSocket, F_GETFL, 0);
if(0 > nFlag)
{
closesocket(nSocket);
SocklogError( __FUNCTION__, "fcntl", errno );
}
if (fcntl(nSocket, F_SETFL, nFlag|O_NONBLOCK) < 0)
{
closesocket(nSocket);
SocklogError( __FUNCTION__, "fcntl", errno );
}
if ( !(pSession = m_pExecSockDataMgr->NewSession( nSocket, sRemote )) )
{
closesocket( nSocket );
SocklogError( __FUNCTION__, "用户队列已经满了。", ERROR_SUCCESS );
m_SessionFullTick = GetTickCount() + 10 * 1000;
return;
}
// AdjustSocketSendBufSize( nSocket, 32 * 1024 );
}
建立新的会话并添加会话列表
PRUNGATEUSERSESSION ExecSockDataMgr::NewSession(SOCKET nSocket, SOCKADDRIN RemoteAddr)
{
PRUNGATEUSERSESSION pNewSession = NULL;
EnterCriticalSection( &m_SessionLock );
pNewSession = m_SessionAllocator.allocObject();//会话分配器
pNewSession->nSocket = INVALID_SOCKET;
pNewSession->SendBuf.nOffset = 0;
pNewSession->dwCloseTick = 0;
pNewSession->boMarkToClose = false;
pNewSession->boRemoteClosed = false;
PRUNGATEUSERSESSION *pSessionList = m_SessionList;
for (INT_PTR i=m_SessionList.count()-1; i>-1; --i)
{
if (!pSessionList[i])
{
pSessionList[i] = pNewSession;
pNewSession->nIndex = (int)i;
pSessionList = NULL;
break;
}
}
if (pSessionList)//找不到空闲的位置,就添加到最后面,需要拓展列表的长度
{
pNewSession->nIndex = (int)m_SessionList.add(pNewSession);
}
LeaveCriticalSection( &m_SessionLock );
if ( pNewSession )//内存地址可能改变
{
pNewSession->SockAddr= RemoteAddr;
pNewSession->nPlayerIndex= -1;
pNewSession->pPlayer= NULL;
pNewSession->wPacketVerifyKey= 0;
pNewSession->nRecvPacketCount=0;
pNewSession->nSendPacketCount=0;
pNewSession->btUserState= eGUSWaitRequestKey;/