服务器之间的被动连接的设计和实现,本文的代码内容是以自定义被动连接socket来体现。
功能是服务器之间的数据收发的被动连接的处理。
应用如:数据服务器的数据服务器对象是继承于自定义被动连接socket的,处理逻辑服务器的连接活动。
设计上:
启动两个线程:
(1)接收连接线程(增加活动会话)
(2)启动数据收发线程:
处理所有的会话上的数据,接收数据并拷贝到缓存,和处理发送队列数据发送 。
1、自定义服务器socket线程启动
创建用于接受连接的套接字,绑定套接字到地址和端口,监听端口
启动线程:
1)连接接受线程
2)启动数据处理线程
BOOL CCustomServerSocket::Startup()
{
int nError;
if ( TRUE == InterlockedCompareExchange(&m_boStoped, FALSE, TRUE) )//设置线程启动标识
{
//创建用于接受连接的套接字
nError = createSocket(&m_nSocket);
if ( nError )
{
logError("创建%s服务套接字失败,%d", m_sServiceName,nError);
return FALSE;
}
//绑定套接字到地址和端口
nError = bind(m_sBindHost, (INT)m_nBindPort);
if ( nError )
{
logError("绑定%s服务器套接字到%s:%d失败,Error %d", m_sServiceName, m_sBindHost, m_nBindPort,nError);
return FALSE;
}
//监听
nError = listen();
if ( nError )
{
logError("无法在%s:%d端口监听%s服务,Error %d", m_sBindHost, m_nBindPort, m_sServiceName,nError);
return FALSE;
}
//调用启动函数(启动前可做一些操作)
if ( !DoStartup() )
{
return FALSE;
}
//启动接受连接的线程
m_boAcceptThreadStoped = FALSE;
#ifdef WINDOWS
m_hAcceptThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ServerSocketAcceptThreadRoutine, this, 0, NULL);
if ( !m_hAcceptThread )
{
logError("创建%s服务器连接接受线程失败,error %d", m_sServiceName,GetLastError());
return FALSE;
}
//启动数据处理线程
m_hDataThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ServerSocketDataThreadRoutine, this, 0, NULL);
if ( !m_hDataThread )
{
logError("创建%s服务器数据处理线程失败,error %d", m_sServiceName,GetLastError());
return FALSE;
}
#else
//连接接受线程
if(0 != pthread_create(&m_hAcceptThread, 0, (LPTHREAD_START_ROUTINE)(ServerSocketAcceptThreadRoutine), this))
{
logError("创建%s服务器连接接受线程失败,error %d", m_sServiceName,errno);
return FALSE;
}
//启动数据处理线程
if(0 != pthread_create(&m_hDataThread, 0, (LPTHREAD_START_ROUTINE)(ServerSocketDataThreadRoutine), this))
{
logError("创建%s服务器数据处理线程失败,error %d", m_sServiceName,errno);
return FALSE;
}
#endif
}
return TRUE;
}
2、接收连接线程
不断循环接收连接,并创建客户端连接对象,设置连接收发缓冲区,并添加到客户端连接对象列表
VOID CCustomServerSocket::ServerSocketAcceptThreadRoutine(CCustomServerSocket *lpServer)
{
int nError;
SOCKET nSock;
CCustomServerClientSocket *pClient;
SOCKADDR_IN addr_In;
while ( !lpServer->m_boStoped )
{
nError = lpServer->accept(&nSock, 3000, &addr_In);
//成功
if ( nError == 0 )
{
//创建客户端连接对象
pClient = lpServer->CreateClientSocket(nSock, &addr_In);
//创建连接对象失败,则关闭套接字
if ( !pClient )
{
closesocket(nSock);
continue;
}
//设置为非阻塞模式
nError = pClient->setBlockMode(false);
if ( nError )
{
logError("无法将%s套接字接受的连接设置为非阻塞模式,%d", lpServer->m_sServiceName,nError);
delete pClient;
continue;
}
//调整接收缓冲区大小(32k)
nError = pClient->setRecvBufSize(32 * 1024);
if ( nError )
{
//此操作的错误可以忽略
logError("无法将%s套接字接受的连接调整接受缓冲区大小,%d", lpServer->m_sServiceName,nError);
}
//调整发送缓冲区大小(32k)
nError = pClient->setSendBufSize(32 * 1024);
if ( nError )
{
//此操作的错误可以忽略
logError("无法将%s套接字接受的连接调整发送缓冲区大小,%d", lpServer->m_sServiceName,nError);
}
lpServer->OnClientConnect(pClient);
if (pClient->connected())
lpServer->m_ClientList.append(pClient);//添加到客户端连接列表
else lpServer->DestroyClientSocket(pClient);
moon::OS::osSleep(1);
continue;
}
//超时
if ( nError == SOCKET_ERROR - 1 )
continue;
//接收连接出错
logError("错误,%d",nError);
moon::OS::osSleep(1000);
break;
}
lpServer->m_boAcceptThreadStoped = TRUE;//标记接受连接的线程已经退出
ExitThread(0);//设置线程退出返回值
}
3、数据收发线程
(1)性能统计和数据收发周期限制
不断执行socket线程例程,控制周期,并计算执行例程的性能统计。
周期控制:
1) 每次循环最多调用两次socket线程例程的函数(数据收发和维持心跳包),最大循环时间4ms(不足的时间会在当次循环末尾休眠该时间)
1) 每次循环最多调用两次socket线程例程的函数(数据收发和维持心跳包),最大循环时间4ms(不足的时间会在当次循环末尾休眠该时间)
性能统计:
1)每隔60s重新统计一次
2)记录循环次数(最大和最小)
3)记录收发时间(最大和最小)
4)记录休眠时间(最大和最小)
2)记录循环次数(最大和最小)
3)记录收发时间(最大和最小)
4)记录休眠时间(最大和最小)
VOID CCustomServerSocket::ServerSocketDataThreadRoutine(CCustomServerSocket *lpServer)
{
TICKCOUNT dwStartTick, dwCurTick, dwRestaticTick = 0;
int nLoopCount;
DWORD dwSleepTick;
lpServer->OnSocketDataThreadStart();
while ( !lpServer->m_boAcceptThreadStoped )
{
lpServer->m_MainProcPerformance.dwTickBegin = dwStartTick = _getTickCount();
//是否重新统计循环性能
if ( dwStartTick >= dwRestaticTick )
{
dwRestaticTick = dwStartTick + 60 * 1000;
lpServer->m_LoopPerformance.nMaxLoop = 0;
lpServer->m_LoopPerformance.nMinLoop = 99999;
lpServer->m_MainProcPerformance.dwMaxTick = 0;
lpServer->m_MainProcPerformance.dwMinTick = 9999;
}
nLoopCount = 0;
while ( TRUE )
{
lpServer->SingleRun();//服务端连接例程(处理连接的客户端)
nLoopCount++;
dwCurTick = _getTickCount();
//连接数据处理线程的单次循环时间限制(单位是毫秒),默认值是4
//最大统计循环时间是4ms
if ( dwCurTick - dwStartTick >= lpServer->m_uLoopTimeLimit )
{
dwSleepTick = 1;
break;
}
//连接数据处理线程的单次循环次数限制,默认值为2
//最大统计循环次数是2
if ( nLoopCount >= lpServer->m_nLoopCountLimit )
{
//每次循环时间是4ms,如果不够就休眠剩下的时间,否则就休眠1ms
dwSleepTick = (DWORD)(lpServer->m_uLoopTimeLimit - (dwCurTick - dwStartTick));
//如果实际休眠值为此值则说明上一步的运算溢出了
if ( dwSleepTick > lpServer->m_uLoopTimeLimit + 2 )
dwSleepTick = (DWORD)(lpServer->m_uLoopTimeLimit + 2);
break;
}
}
//循环次数
lpServer->m_LoopPerformance.nLastLoop = nLoopCount;
//数据收发处理时间
lpServer->m_MainProcPerformance.dwLastTick = dwCurTick - lpServer->m_MainProcPerformance.dwTickBegin;
//休眠时间
lpServer->m_MainSleepPerformance.dwLastTick = dwSleepTick;
//设置统计最大最小循环次数
if ( lpServer->m_LoopPerformance.nMaxLoop < nLoopCount )
{
lpServer->m_LoopPerformance.nMaxLoop = nLoopCount;
}
if ( lpServer->m_LoopPerformance.nMinLoop > nLoopCount )
{
lpServer->m_LoopPerformance.nMinLoop = nLoopCount;
}
//设置统计最大最小时间
if ( lpServer->m_MainProcPerformance.dwMaxTick < lpServer->m_MainProcPerformance.dwLastTick )
{
lpServer->m_MainProcPerformance.dwMaxTick = lpServer->m_MainProcPerformance.dwLastTick;
}
if ( lpServer->m_MainProcPerformance.dwMinTick > lpServer->m_MainProcPerformance.dwLastTick )
{
lpServer->m_MainProcPerformance.dwMinTick = lpServer->m_MainProcPerformance.dwLastTick;
}
//设置休眠的最大最小时间
if ( lpServer->m_MainSleepPerformance.dwMaxTick < dwSleepTick )
{
lpServer->m_MainSleepPerformance.dwMaxTick = dwSleepTick;
}
if ( lpServer->m_MainSleepPerformance.dwMinTick > dwSleepTick )
{
lpServer->m_MainSleepPerformance.dwMinTick = dwSleepTick;
}
//休眠
moon::OS::osSleep(dwSleepTick);
}
if ( lpServer->connected() )
{
lpServer->close();
}
lpServer->OnSocketDataThreadStop();
//关闭所有连接
lpServer->CloseAllClients();
ExitThread(0);//设置线程退出返回值
}
(2)处理客户端连接
处理存活的客户端连接
VOID CCustomServerSocket::SingleRun()
{
//处理连接的客户端
ProcessClients();
//调用例行函数
OnRun();
}
处理所有存活的客户端连接(被动连接socket对象)
VOID CCustomServerSocket::ProcessClients()
{
INT_PTR i;
CCustomServerClientSocket *pClient;
//循环处理每个客户端连接
m_ClientList.flush();
//必须降序循环,因为列表中的数据可能在循环中被移除
for ( i=m_ClientList.count() - 1; i>-1; --i )
{
pClient = m_ClientList[i];
//处理活动的连接
pClient->Run();
//删除断开的连接
if ( !pClient->connected() )
{
m_ClientList.lock();
m_ClientList.remove(i);
m_ClientList.unlock();
DestroyClientSocket(pClient);
continue;
}
}
}
活的连接的处理
VOID CCustomServerClientSocket::SingleRun()
{
super::SingleRun();
//发送保持连接消息(服务器主动保持长连接)
if ( m_boActiveKeepAlive && connected() )
{
if ( _getTickCount() - m_dwMsgTick >= 10 * 1000 )
{
SendKeepAlive();
}
}
}
socket数据接收和发送
VOID CCustomWorkSocket::SingleRun()
{
//接收数据
if ( connected() )
ReadSocket();//接收数据到接收缓冲区
//处理接受到的数据包
if ( connected() )
ProcessRecvBuffers(m_pProcRecvBuffer);//拷贝数据和粘包
//调用例行函数
OnRun();
//发送数据
if ( connected() && m_bSendData)
{
SendSocketBuffers();//发送发送队列中的数据包
}
}
数据接收。接收数据到接收缓冲区。每次接受数据长度最大值限制4096字节,接受缓冲区大小不够时会增长4096*2字节大小。
VOID CCustomWorkSocket::ReadSocket()
{
static const int OnceRecvSize = 4096;//每次接收的数据的最大值
int nError;
TICKCOUNT dwCurTick = _getTickCount();
while ( TRUE )
{
//增长接收缓冲区大小
if ( m_pRecvBuffer->nSize - m_pRecvBuffer->nOffset < OnceRecvSize * 2 )
{
size_t nPointer = m_pRecvBuffer->pPointer - m_pRecvBuffer->pBuffer;
m_pRecvBuffer->nSize += OnceRecvSize * 2;
m_pRecvBuffer->pBuffer = (char*)realloc(m_pRecvBuffer->pBuffer, m_pRecvBuffer->nSize);
m_pRecvBuffer->pPointer = m_pRecvBuffer->pBuffer + nPointer;
}
//从套接字读取数据
nError = recv(&m_pRecvBuffer->pBuffer[m_pRecvBuffer->nOffset], OnceRecvSize);
if ( nError <= 0 )
break;
m_pRecvBuffer->nOffset += nError;
m_pRecvBuffer->pBuffer[m_pRecvBuffer->nOffset] = 0;
m_dwMsgTick = dwCurTick;
}
}