游戏服务器之服务器之间的主动连接
2014-02-10 01:24
281 查看
游戏服务器之服务器之间的主动连接的设计和实现,本文的代码内容是以自定义主动连接socket来体现。
设计上:
创建主动连接socket线程,功能如下
(1)处理主动连接到其他服务器
(2)数据的收发
(3)发送心跳
周期控制:
1) 每次循环最多调用两次例程socket线程的函数,最大循环时间4ms(不足的时间会在当次循环末尾休眠该时间)
性能统计:
1)每隔60s重新统计一次
2)记录循环次数(最大和最小)
3)记录收发时间(最大和最小)
4)记录休眠时间(最大和最小)
对每项业务处理需要先判断连接是否正常。
设计上:
创建主动连接socket线程,功能如下
(1)处理主动连接到其他服务器
(2)数据的收发
(3)发送心跳
1、自定义客户端连接socket启动
创建连接socket线程。BOOL CCustomClientSocket::Startup() { if ( TRUE == InterlockedCompareExchange(&m_boStoped, FALSE, TRUE) ) { #if PLATFORM == WINDOWS32 || PLATFORM == WINDOWS64 m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CustomClientSocketWorkRoutine, this, 0, &m_dwThreadId); if ( !m_hThread ) { logError("创建%s通信线程失败,%d", m_sClientName, GetLastError()); return FALSE; } #endif #if PLATFORM == LINUX32 || PLATFORM == LINUX64 if(0 != pthread_create(&m_hThread, 0, (void *(*)(void*))(&CustomClientSocketWorkRoutine), this)) { logError("创建%s通信线程失败,%d", m_sClientName,errno); return false; } #endif } return TRUE; }
2、创建主动连接线程
(1)性能检测和周期控制
不断执行socket线程例程,控制周期,并计算执行例程的性能统计。周期控制:
1) 每次循环最多调用两次例程socket线程的函数,最大循环时间4ms(不足的时间会在当次循环末尾休眠该时间)
性能统计:
1)每隔60s重新统计一次
2)记录循环次数(最大和最小)
3)记录收发时间(最大和最小)
4)记录休眠时间(最大和最小)
VOID STDCALL CCustomClientSocket::CustomClientSocketWorkRoutine(CCustomClientSocket *lpClient) { static const int MaxLoop = 2;//最大循环次数 static const TICKCOUNT MaxCPU = 4;//最大循环时间 TICKCOUNT dwStartTick, dwCurTick, dwRestaticTick = 0; int nLoopCount; DWORD dwSleepTick; lpClient->OnWorkThreadStart(); while ( !lpClient->m_boStoped ) { lpClient->m_MainProcPerformance.dwTickBegin = dwStartTick = _getTickCount();//开始性能计算时间 //是否重新统计循环性能(每隔60s重新统计) if ( dwStartTick >= dwRestaticTick ) { dwRestaticTick = dwStartTick + 60 * 1000; lpClient->m_LoopPerformance.nMaxLoop = 0; lpClient->m_LoopPerformance.nMinLoop = 99999; lpClient->m_MainProcPerformance.dwMaxTick = 0; lpClient->m_MainProcPerformance.dwMinTick = 9999; } nLoopCount = 0; while ( TRUE ) { lpClient->SingleRun();//客户端连接例程(处理数据收发和心跳) nLoopCount++; dwCurTick = _getTickCount();//当前时间 if ( dwCurTick - dwStartTick >= MaxCPU )//最大循环时间(4ms) { dwSleepTick = 1; break; } if ( nLoopCount >= MaxLoop )//最大循环次数2 { ////每次循环时间4ms ,没使用完的时间就休眠 dwSleepTick = (DWORD)(MaxCPU - (dwCurTick - dwStartTick)); //如果实际休眠值为此值则说明上一步的运算溢出了 if ( dwSleepTick > MaxCPU + 2 ) dwSleepTick = MaxCPU + 2; break; } } //循环次数 lpClient->m_LoopPerformance.nLastLoop = nLoopCount; //收发使用时间 lpClient->m_MainProcPerformance.dwLastTick = dwCurTick - lpClient->m_MainProcPerformance.dwTickBegin; //休眠时间 lpClient->m_MainSleepPerformance.dwLastTick = dwSleepTick; //记录循环次数(最大最小) if ( lpClient->m_LoopPerformance.nMaxLoop < nLoopCount ) { lpClient->m_LoopPerformance.nMaxLoop = nLoopCount; } if ( lpClient->m_LoopPerformance.nMinLoop > nLoopCount ) { lpClient->m_LoopPerformance.nMinLoop = nLoopCount; } //记录收发时间(最大最小) if ( lpClient->m_MainProcPerformance.dwMaxTick < lpClient->m_MainProcPerformance.dwLastTick ) { lpClient->m_MainProcPerformance.dwMaxTick = lpClient->m_MainProcPerformance.dwLastTick; } if ( lpClient->m_MainProcPerformance.dwMinTick > lpClient->m_MainProcPerformance.dwLastTick ) { lpClient->m_MainProcPerformance.dwMinTick = lpClient->m_MainProcPerformance.dwLastTick; } //记录休眠时间(最大最小) if ( lpClient->m_MainSleepPerformance.dwMaxTick < dwSleepTick ) { lpClient->m_MainSleepPerformance.dwMaxTick = dwSleepTick; } if ( lpClient->m_MainSleepPerformance.dwMinTick > dwSleepTick ) { lpClient->m_MainSleepPerformance.dwMinTick = dwSleepTick; } moon::OS::osSleep(dwSleepTick); } if ( lpClient->connected() ) { lpClient->close(); } lpClient->OnWorkThreadStop(); ExitThread(0);//设置线程退出返回值 }
(2)自定义客户端连接socket例程
在例程中保持心跳消息(保持长连接)。VOID CCustomClientSocket::SingleRun() { // TICKCOUNT dwCurTick = _getTickCount(); //连接到服务器 if ( !connected() ) ConnectToServer();//创建连接socket并连接 super::SingleRun(); //发送保持连接消息 if ( connected() ) { if ( _getTickCount() - m_dwMsgTick >= 10 * 1000 ) { SendKeepAlive();//10s 一次心跳包 } } }
(3)创建连接socket并连接
创建socket(主动连接socket对象)并主动连接到服务器,设置socket属性。BOOL CCustomClientSocket::ConnectToServer() { int nErr; //如果已连接则直接返回 if ( connected() ) { return TRUE; } TICKCOUNT dwCurTick = _getTickCount(); //创建套接字 if ( getSocket() == INVALID_SOCKET ) { SOCKET sock; nErr = createSocket(&sock); if ( nErr ) { logError("创建%s客户端套接字失败,error %s %d", m_sClientName,nErr); return FALSE; } m_nSocket = sock; //调整发送和接收缓冲大小 nErr = setSendBufSize(32 * 1024); if ( nErr ) { logError("调整%s套接字发送缓冲长度失败 %s %d", m_sClientName,nErr); return FALSE; } nErr = setRecvBufSize(32 * 1024); if ( nErr ) { logError("调整%s套接字接收缓冲长度失败,%d", m_sClientName,nErr); return FALSE; } } //连接到会话服务器 if ( dwCurTick >= m_dwReconnectTick ) { m_dwReconnectTick = dwCurTick + 5 * 1000; nErr = connect(m_sSrvHost,(INT) m_nSrvPort); if ( nErr ) { logError("连接到%s服务器失败", m_sClientName ); return FALSE; } //调整为非阻塞模式 nErr = setBlockMode(FALSE); if ( nErr ) { logError("调整%s套接字接为非阻塞模式失败,%d", m_sClientName,nErr); return FALSE; } m_dwConnectTick = m_dwMsgTick = dwCurTick; return TRUE; } return FALSE; }
(4)连接socket收发数据
接收数据、执行例程、发送数据。对每项业务处理需要先判断连接是否正常。
VOID CCustomWorkSocket::SingleRun() { //接收数据 if ( connected() ) ReadSocket(); //处理接受到的数据包 if ( connected() ) ProcessRecvBuffers(m_pProcRecvBuffer); //调用例行函数 OnRun(); //发送数据 if ( connected() && m_bSendData) { SendSocketBuffers(); } }
3、自定义客户端连接socket关闭
设置关闭标识、关闭线程、清理发送缓冲区和线程idVOID CCustomClientSocket::Stop() { if ( FALSE == InterlockedCompareExchange(&m_boStoped, TRUE, FALSE) ) { CloseThread(m_hThread);//关闭线程(等待回收子线程线程并取消线程) #define CloseThread(ht){ waitpid( ht, 0, 0 ); pthread_cancel( ht ); } ClearSendBuffers(); m_dwThreadId = 0; } }
相关文章推荐
- 游戏服务器之服务器之间的被动连接
- 管理蓝牙SDP记录和游戏服务器之间连接
- 游戏服务器之主动连接线程池
- linux多台服务器之间ssh连接无需密码
- 如何判断本客户端 SOCKET 与服务器 之间的连接状态.
- 什么是心跳线?心跳线,主要用于主从服务器之间,是连接工作机与备份机的网线
- ActiveMQ学习笔记01 - 客户端与服务器之间的传输连接
- 游戏服务器之长连接服务器(python)(1)
- SqlServer 不同服务器之间数据库连接、数据库登录、数据传递
- Unity3D 游戏引擎之C#使用Socket与HTTP连接服务器传输数据包
- 服务器和存储之间一定要连接光纤交换机吗?
- cocos2dx 实现连接登陆服务器认证后进入游戏
- Unity3D 游戏引擎之C#使用Socket与HTTP连接服务器传输数据包
- ActiveMQ学习笔记01 - 客户端与服务器之间的传输连接
- 网络游戏服务器构架设计(二):刀剑Online - 连接负载服务器CLS
- 游戏大厅 从基础开始(3.5)——最吸引眼球的部分 客户端与服务器的连接 的实现
- ssh 多台服务器之间连接(linux)
- Unity3D 游戏引擎之C#使用Socket与HTTP连接服务器传输数据包
- 游戏服务器之被动连接线程池