前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >游戏服务器之多线程发送(下)

游戏服务器之多线程发送(下)

作者头像
李海彬
发布2018-03-22 16:38:18
6340
发布2018-03-22 16:38:18
举报
文章被收录于专栏:Golang语言社区

5、发送缓冲区数据

检查可发送该线程的相关联的所有会话上的发送缓冲区的数据,检查完后,发送会话上的发送缓冲区的数据。

代码语言:javascript
复制
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;  
            }  
        }  
    }  
}  
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-09-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 5、发送缓冲区数据
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档