/** * @file dssocket.cpp * @brief socket封装 * Copyright(c) 2007,上海第九城市游戏研发部 * All rights reserved * 文件名称: dssocket.cpp * 摘 要: 用于dsiocp,参考:msdn,<> (second edition) * 作 者: dzj * 完成日期: 2008.05.16-2008.05.19 * */ #include "dssocket.h" #include "dsiocp.h" #ifdef USE_DSIOCP //LPFN_TRANSMITFILE CDsSocket::m_pfnTransmitFile; long CDsSocket::m_globalSessionID; ACE_Mutex CDsSocket::m_sessionIDLock;//全局sessionID写锁; ///初始化网络环境; bool InitNetEnv() { WSADATA wsaData; int ret = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( 0 != ret ) { return false; } return true; } ///重置网络环境; void ResetNetEnv() { if ( WSACleanup() == SOCKET_ERROR ) { //error occur; } return; } CDsSocket::~CDsSocket() { PoolObjInit(); closesocket( m_hSocket ); } void CDsSocket::PoolObjInit() { //尽量短地使用写锁; ACE_GUARD( ACE_Thread_Mutex, guard, m_usingLock ); TRY_BEGIN; ReleseSendBuf(); m_bIsInConn = false;//每次回收过后必定不再对应一个连入连接; //if ( NULL != m_pPerIOData )//最后一个未返回的recv; //{ // if ( NULL != g_poolPerIOData ) // { // g_poolPerIOData->Release( m_pPerIOData ); // m_pPerIOData = NULL; // } //} //1027.dbg,InitPendingSendNum();//初始化pendingsendnum; AutoSetSessionID(); memset( m_strAddr, 0, sizeof(m_strAddr) ); m_sPort = 0; ::InterlockedExchange( &m_outstandAcceptNum, 0 );//for listen socket; ////BOOL isreuseok = m_pfnTransmitFile( m_hSocket, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET );//reuse socket; //if ( !isreuseok ) //{ // int syserror = GetLastError(); // D_WARNING( "TransmitFile重用socket失败,错误代码:%d", syserror ); //} SetNonBlocking();//默认置为非阻塞模式; SetCloseNoWait();//hard close; InitIsDisConnecting(); ResetAppNotified(); return; TRY_END; return; } bool CDsSocket::SendInnerBuf() { ACE_GUARD_RETURN( ACE_Thread_Mutex, guard, m_usingLock, false ); TRY_BEGIN; //UniqueSocket的GetUniqueObj保证发送给目标对象,Socket内部的RsvSessionID保证目标对象没有被重用; if ( IsReused() ) { //socket已被回收,且暂时没有被别的连接重用; return false; } if ( ! SendBuffSessionIDCheck() ) { //socket已被回收,并且已被另一个连接重用; return false; } bool isSendOK = true; DsIOBuf* pTmpSendBuf = NULL; if ( !(m_pListSendBuf.empty()) ) { for ( list< DsIOBuf* >::iterator iBuf=m_pListSendBuf.begin(); iBuf!=m_pListSendBuf.end(); ++iBuf ) { pTmpSendBuf = *iBuf; if ( NULL == pTmpSendBuf ) { continue; } if ( !isSendOK ) { //前面已经发送不成功了,释放余下的待发dsiobuf,由于本函数返回false后,调用者会删去本socket,因此不用担心后续包错误发送导致解析错; //g_poolUniDssocket->Release( pTmpSendBuf->pUniqueSocket ); g_poolDsIOBuf->Release( pTmpSendBuf ); continue; } PerIOData* pPerIoData = NULL; DWORD bytesSend = 0ul; //执行数据发送; pPerIoData = g_poolPerIOData->RetrieveOrCreate(); if ( NULL == pPerIoData ) { TRY_BEGIN; D_ERROR( "SendInnerBuf:g_poolPerIOData,内存分配失败\n" ); TRY_END; isSendOK = false; continue; } pPerIoData->opType = IOT_WRITE; memset( &(pPerIoData->overLapped), 0, sizeof( pPerIoData->overLapped ) ); pPerIoData->pAssociSocket = this; pPerIoData->pDsIOBuf = pTmpSendBuf; pPerIoData->refSendBuf.len = pTmpSendBuf->GetInnerLen(); pPerIoData->refSendBuf.buf = pTmpSendBuf->GetInnerBuf(); int ret = 0; //暴汗,这个bug又找了一天,by dzj, 08.05.19, WSASend( pDsSocket->GetSocket(), &(pPerIoData->refSendBuf), 1, &bytesSend, 0, &(pPerIoData->overLapped), NULL ); //RsvPendingSessionID();//异步操作前保存ID号,如果异步操作完成时ID号已发生变化,则说明此过程中socket已被重用; ret = WSASend( GetSocket(), &(pPerIoData->refSendBuf), 1, &bytesSend, 0, &(pPerIoData->overLapped), NULL ); if ( 0 != ret ) { int nerr = WSAGetLastError(); if ( WSA_IO_PENDING != nerr ) { //D_ERROR( "WSASend 错误:%d\n", nerr ); //g_poolUniDssocket->Release( pPerIoData->pDsIOBuf->pUniqueSocket ); g_poolDsIOBuf->Release( pPerIoData->pDsIOBuf ); pPerIoData->pDsIOBuf = NULL; g_poolPerIOData->Release( pPerIoData );//回收periodata; isSendOK = false;//准备释放余下的待发dsiobuf; continue; } } //1027.debug,IncPendingSendNum(); }//发送端口中的每一个缓存; }//发送端口缓存队列; //发送数据已传递给iocp,清socket的pTmpSendList; ResetSendList(); return isSendOK; TRY_END; return false; } #endif //USE_DSIOCP