游戏服务器之多线程发送(下)
时间:2022-05-05
本文章向大家介绍游戏服务器之多线程发送(下),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
5、发送缓冲区数据
检查可发送该线程的相关联的所有会话上的发送缓冲区的数据,检查完后,发送会话上的发送缓冲区的数据。
VOID ExecSockDataMgr::CheckSendSessionBuffers(PEXECDATASENDTHREAD pSendThread)
{
int nErr, nRemainSize;
char *pBuffer;
PRUNGATEUSERSESSION *pSessionList = m_SessionList;
PRUNGATEUSERSESSION pSession;
pSendThread->boSendEWouldBlock = false;
pSendThread->boSendFewBuffer = false;
//优化锁处理
//(1)在开始时就分配65535的会话列表大小,在一个逻辑网关上不会有超出这个大小的有效会话数量(所以会话列表的操作不需要加没有加会话列表锁)
//(2)会话的释放会置空会话列表的成员,会话的nSocket 是在最后才初始化的,所以可以判断pSession->nSocket != INVALID_SOCKET 来判断会话的初始化
//后的有效性,根据pSession->boMarkToClose和pSession->boRemoteClosed 来判断会话是否被关闭(所以不需要加会话锁)
//(3)发送失败会标记该会话被关闭
INT_PTR nCount = m_SessionList.count();
for ( INT_PTR nIndex = pSendThread->nThreadIdx; nIndex < nCount; nIndex += m_nSendThreadCount )
{
pSession = pSessionList[nIndex];
if (!pSession)
continue;
if ( pSession->nSocket != INVALID_SOCKET && !pSession->boMarkToClose && !pSession->boRemoteClosed )//检查该会话处于正常状态
{
if ( !pSession->boSendAvaliable )
{
if ( _getTickCount() >= pSession->dwSendTimeOut )//检查会话的发送时间(等到发送的时间再发送)
{
pSession->boSendAvaliable = true;//到了可发送时间则标记可发送
pSession->dwSendTimeOut = 0;
}
else continue;
}
// 这里可以不加会话锁,因为数据接收处理线程回收会话资源是根据关闭标识并延时10s的(这里的锁需要验证),发送缓冲区的数据操作在本线程内
//(如果实在要加锁,对于数据接收处理线程会修改会话,因为不会有其他发送线程使用该会话,所以可以是互斥量)
if ( TRYLOCK_SESSION_SEND( pSession ) )
{
nRemainSize = pSession->SendBuf.nOffset;//该会话的缓冲区的有效数据大小
if ( nRemainSize > 4096 * 1024 )//发送缓冲区过长的会话会被关闭(这是异常现象,一般不会出现)
{
UNLOCK_SESSION_SEND( pSession );
CloseSession( pSession );
nRemainSize = 0;
logWarn("关闭了一个发送数据队列大于4MB的连接。");
continue;
}
if ( nRemainSize )
{
pBuffer = pSession->SendBuf.lpBuffer;
#ifdef LINUX
nErr = ::send( pSession->nSocket, pBuffer, nRemainSize, MSG_NOSIGNAL);//禁止对端连接关闭时,send()函数向系统发送异常消息brokenpipe
#else
nErr = ::send( pSession->nSocket, pBuffer, nRemainSize, 0 );
#endif
if ( nErr > 0 )//发送成功
{
pSession->nSendPacketCount++;
InterlockedExchangeAdd( (LONG*)&m_dwWaitSendUserSize, -nErr );
InterlockedExchangeAdd( (LONG*)&m_dwSendUserSize, nErr );
if ( nErr < nRemainSize )//如果还有剩余发送数据则把剩余发送数据拷贝到该会话的缓冲区的前部
{
pSendThread->boSendFewBuffer = true;
memcpy( pBuffer, &pBuffer[nErr], nRemainSize - nErr );
nRemainSize -= nErr;
pBuffer[nRemainSize] = 0;
pSession->SendBuf.nOffset = nRemainSize;
}
else
{
pBuffer[0] = 0;
pSession->SendBuf.nOffset = 0;
}
}
else if ( !nErr || WSAGetLastError() != WSAEWOULDBLOCK )//对方关闭了套接字
{
pSession->boRemoteClosed = true;
CloseSession( pSession );
InterlockedExchangeAdd( (LONG*)&m_dwWaitSendUserSize, -nRemainSize );
InterlockedExchangeAdd( (LONG*)&m_dwSendUserSize, nRemainSize );
pBuffer[0] = 0;
pSession->SendBuf.nOffset = 0;
}
else//系统发送缓冲区已满则延时发送
{
pSession->boSendAvaliable = false;
pSession->dwSendTimeOut = _getTickCount() + RUNGATE_SENDCHECK_TIMEOUT;//目前300ms作为发送间隔
pSendThread->boSendEWouldBlock = true;
}
}
UNLOCK_SESSION_SEND( pSession );
}
}
else
{
//会话关闭后减少待发送数据统计值
if ( (nRemainSize = pSession->SendBuf.nOffset) )
{
InterlockedExchangeAdd( (LONG*)&m_dwWaitSendUserSize, -nRemainSize );//减少该逻辑网关上的待发送给用户的有效数据大小
pSession->SendBuf.nOffset = 0;
}
}
}
}
- 内部类
- 初学java之接口基础
- java之内部类
- html学习第一讲(内容html常规控件的的使用)
- uva----(10794) A Different Task
- uva-----(11384)Help is needed for Dexter
- uva------(11464)Even Parity
- java SE学习之线程同步(详细介绍)
- java多线程的常用方法(以及注意事项)
- MFC学习之窗口基础
- java多线程下如何调用一个共同的内存单元(调用同一个对象)
- java之多线程(Thread)
- HDUOJ------3336 Count the string(kmp)
- hduoj------2594 Simpsons’ Hidden Talents
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法