#include "stdafx.h" #include "ClientSession.h" #include "SysException.h" #include "MemNode.h" #include "ClientManager.h" #include "MemPool.h" #include "Player.h" CClientSession::CClientSession(CClientManager& ClientManager) :m_CliManager(ClientManager), m_Connected(false), m_ReadSeqNo(0), m_CurReadSeqNo(0), m_SendSeqNo(0), m_CurSendSeqNo(0), m_PartialMem(NULL), m_MemPool(NULL), m_Player(NULL), m_CliSocket(INVALID_SOCKET), m_UdpSocket(INVALID_SOCKET) { InitializeCriticalSection(&m_csSession); m_MemPool = m_CliManager.GetMemPool(); m_GateSrvIp = "127.0.0.1"; m_GateSrvPort = 0; m_ConnType = 0; } CClientSession::~CClientSession(void) { if (m_CliSocket != INVALID_SOCKET) { CloseSession(); } if (m_UdpSocket != INVALID_SOCKET) { CloseSession(); } DeleteCriticalSection(&m_csSession); } int CClientSession::OpenSession(const string& strServerIp, int nPort) { if (m_UdpSocket != INVALID_SOCKET) { CloseSession(); } m_ConnType = 1; //创建Socket m_CliSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_CliSocket == INVALID_SOCKET) { throw CSysException("socket failed in CClientSession", ::WSAGetLastError()); } //设置socket IO模型为nonblocking形式 int nIOMode = 1; if (SOCKET_ERROR == ioctlsocket(m_CliSocket, FIONBIO, (u_long*)&nIOMode)) { //CRobotManager::m_AppLogger.WriteLog("GameRobot.log", "%s", "设置连接为非阻赛失败!"); } ioctlsocket(m_CliSocket, FIONBIO, (u_long*)&nIOMode); //设置接收缓冲区 int nNetBufSize = NETBUF; int nLen = sizeof(int); if (SOCKET_ERROR != setsockopt(m_CliSocket, SOL_SOCKET, SO_RCVBUF, (char*)&nNetBufSize, nLen)) { getsockopt(m_CliSocket, SOL_SOCKET, SO_RCVBUF, (char*)&nNetBufSize, &nLen); if (nNetBufSize != NETBUF) { //CRobotManager::m_AppLogger.WriteLog("GameRobot.log", "%s", "设置接收缓冲区宽度没有成功!"); } } nLen = sizeof(int); nNetBufSize = NETBUF; if (SOCKET_ERROR != setsockopt(m_CliSocket, SOL_SOCKET, SO_SNDBUF, (char*)&nNetBufSize, nLen)) { getsockopt(m_CliSocket, SOL_SOCKET, SO_SNDBUF, (char*)&nNetBufSize, &nLen); if (nNetBufSize != NETBUF) { //CRobotManager::m_AppLogger.WriteLog("GameRobot.log", "%s", "设置发送缓冲区宽度没有成功!"); } } m_CliManager.AddToIocp(this); //构建服务端信息 SOCKADDR_IN ServerAddr; memset(&ServerAddr, 0, sizeof(SOCKADDR_IN)); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(nPort); ServerAddr.sin_addr.s_addr = inet_addr(strServerIp.c_str()); try { //获得ConnectEx的函数指针 GUID guid = WSAID_CONNECTEX; LPFN_CONNECTEX lpfnConnectEx = NULL; DWORD dwBytes = 0; if (0 != WSAIoctl(m_CliSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(GUID), &lpfnConnectEx, sizeof(LPFN_CONNECTEX), &dwBytes, NULL, 0)) { throw CSysException("connect failed in CClientSession-OpenSession.", ::WSAGetLastError()); } //绑定到一个本地端口 memset(&m_LocalAddr, 0, sizeof(SOCKADDR_IN)); m_LocalAddr.sin_family = AF_INET; m_LocalAddr.sin_port = htons(0); m_LocalAddr.sin_addr.s_addr = INADDR_ANY; if (SOCKET_ERROR == bind(m_CliSocket, reinterpret_cast(&m_LocalAddr), sizeof(m_LocalAddr))) { DWORD dwErrCode = WSAGetLastError(); throw CSysException("connect failed in CClientSession-OpenSession.", dwErrCode); } //获得连接的本地地址 int nAddrLen = sizeof(SOCKADDR_IN); if (SOCKET_ERROR == getsockname(m_CliSocket, reinterpret_cast(&m_LocalAddr), &nAddrLen)) { DWORD dwErrCode = WSAGetLastError(); throw CSysException("get socket name failed in CClientSession-OpenSession.", dwErrCode); } //连接服务端 CMemNode* pMemMode = m_MemPool->NewMemNode(); pMemMode->SetBufType(IO_CONN); pMemMode->SetUseSize(1); BOOL bConnRet = lpfnConnectEx(m_CliSocket, reinterpret_cast(&ServerAddr), sizeof(ServerAddr), NULL, 0, NULL, pMemMode); if (!bConnRet) { DWORD dwErrCode = WSAGetLastError(); if (dwErrCode != ERROR_IO_PENDING) { m_MemPool->ReleaseMemNode(pMemMode); throw CSysException("connect failed in CClientSession-OpenSession.", dwErrCode); } } } catch (...) { } return 0; } int CClientSession::CloseSession() { SOCKET* sock = m_ConnType == 1 ? &m_CliSocket : &m_UdpSocket; if (*sock != INVALID_SOCKET) { m_Connected = false; setsockopt(m_CliSocket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); shutdown(*sock, SD_SEND); closesocket(*sock); *sock = INVALID_SOCKET; EnterCriticalSection(&m_csSession); m_ReadSeqNo = 0; m_CurReadSeqNo = 0; for (map::iterator Ite = m_ReadMap.begin() ; Ite != m_ReadMap.end(); Ite++) { m_MemPool->ReleaseMemNode(Ite->second); } m_ReadMap.clear(); m_SendSeqNo = 0; m_CurSendSeqNo = 0; for (map::iterator Ite = m_SendMap.begin(); Ite != m_SendMap.end(); Ite++) { m_MemPool->ReleaseMemNode(Ite->second); } m_ReadMap.clear(); if (m_PartialMem) { m_MemPool->ReleaseMemNode(m_PartialMem); m_PartialMem = NULL; } LeaveCriticalSection(&m_csSession); if (m_ConnType == 1) { OnClose(); } } return 0; } int CClientSession::ReadData(CMemNode* pMemNode) { if (!m_Connected) { return 0; } if (pMemNode == NULL) { u_long ulDataLen = 0; GetSockDataLen(ulDataLen); if (ulDataLen > 5120) { char szBuf[MAX_PATH]; sprintf(szBuf, "Account:%s, DataLen:%d.\n", GetAccount().c_str(), ulDataLen); OutputDebugString(szBuf); } pMemNode = m_MemPool->NewMemNode(ulDataLen); } pMemNode->SetBufType(IO_RECV); EnterCriticalSection(&m_csSession); pMemNode->SetSeqNum(m_ReadSeqNo); m_ReadSeqNo = (m_ReadSeqNo + 1) % MAXIMUMSEQUENSENUMBER; DWORD dwNumBytes = 0; DWORD dwFlags = 0; WSABUF wsaBuf; wsaBuf.buf = pMemNode->GetBufferPrt() + pMemNode->GetUsedSize(); wsaBuf.len = pMemNode->GetSize() - pMemNode->GetUsedSize(); try { DWORD dwRet; dwRet = WSARecv(m_ConnType == 1 ? m_CliSocket : m_UdpSocket, &wsaBuf, 1, &dwNumBytes, &dwFlags, pMemNode, NULL); LeaveCriticalSection(&m_csSession); if (SOCKET_ERROR == dwRet) { DWORD dwErrCode = ::WSAGetLastError(); if (dwErrCode != ERROR_IO_PENDING) { throw CSysException("throw an exception in CClientSession-ReadData", ::WSAGetLastError()); } } } catch (...) { CloseSession(); m_MemPool->ReleaseMemNode(pMemNode); } return 0; } int CClientSession::SendData(CMemNode* pMemNode) { if (!m_Connected) { ReleaseMem(pMemNode); return 0; } pMemNode->SetBufType(IO_SEND_REQ); PostQueuedCompletionStatus(m_CliManager.GetIocp(), pMemNode->GetUsedSize(), (ULONG_PTR)this, pMemNode); return 0; } void CClientSession::SetAccount(const string& strAccount) { m_Account = strAccount; } CMemNode* CClientSession::GetCurData(CMemNode* pMemNode) { CMemNode* pRetMemNode = NULL; if (NULL != pMemNode) { unsigned long ulSeqNo = pMemNode->GetSeqNum(); EnterCriticalSection(&m_csSession); //如果是当前要处理的序列号 if (ulSeqNo == m_CurReadSeqNo) { m_CurReadSeqNo = (m_CurReadSeqNo + 1) % MAXIMUMSEQUENSENUMBER; LeaveCriticalSection(&m_csSession); pRetMemNode = pMemNode; } //如果不是当前要处理的序列号,则要缓存 else { map::iterator Ite = m_ReadMap.find(pMemNode->GetSeqNum()); if (Ite == m_ReadMap.end()) { m_ReadMap[pMemNode->GetSeqNum()] = pMemNode; } else { char szBuf[MAX_PATH]; sprintf(szBuf, "Account:%s, SeqNo:%d, SeqNo Dublicate!\n", m_Account.c_str(), pMemNode->GetSeqNum()); OutputDebugString(szBuf); } LeaveCriticalSection(&m_csSession); } } else { EnterCriticalSection(&m_csSession); map::iterator Ite = m_ReadMap.find(m_CurReadSeqNo); if (Ite != m_ReadMap.end()) { m_CurReadSeqNo = (m_CurReadSeqNo + 1) % MAXIMUMSEQUENSENUMBER; pRetMemNode = Ite->second; m_ReadMap.erase(Ite); } LeaveCriticalSection(&m_csSession); } return pRetMemNode; } void CClientSession::ProcMemNode(CMemNode* pMemNode) { //调整包序号 CMemNode* pNewMemNode = NULL; EnterCriticalSection(&m_csSession); pNewMemNode = GetCurData(pMemNode); while (pNewMemNode != NULL) { m_Player->OnDataRecv(pNewMemNode); pNewMemNode = GetCurData(NULL); } LeaveCriticalSection(&m_csSession); } CMemNode* CClientSession::PrepareMem() { return m_MemPool->NewMemNode(); } void CClientSession::ReleaseMem(CMemNode *pMemNode) { m_MemPool->ReleaseMemNode(pMemNode); } void CClientSession::SetPlayer(CPlayer* pPlayer) { m_Player = pPlayer; } int CClientSession::OnConnection() { m_Player->OnConnectionOpen(); return 0; } int CClientSession::OnClose() { m_Player->OnConnectionClose(); return 0; } int CClientSession::OpenAssignSrv(const string& strAssignSvrIp, int nAssignSvrPort) { m_ConnType = 0; if (INVALID_SOCKET != m_UdpSocket) { closesocket(m_UdpSocket); m_UdpSocket = INVALID_SOCKET; } m_UdpSocket = socket(AF_INET, SOCK_DGRAM, 0); if (m_UdpSocket == INVALID_SOCKET) { throw CSysException("socket failed in CClientSession", ::WSAGetLastError()); } m_CliManager.AddToIocp(this); sockaddr_in ASAddr; memset(&ASAddr, 0, sizeof(sockaddr_in)); ASAddr.sin_family = AF_INET; ASAddr.sin_port = htons(nAssignSvrPort); ASAddr.sin_addr.s_addr = inet_addr(strAssignSvrIp.c_str()); int nResult = connect(m_UdpSocket, (sockaddr*)&ASAddr, sizeof(sockaddr_in)); if (nResult == SOCKET_ERROR) { DWORD dwErrCode = ::WSAGetLastError(); throw CSysException("socket connect in CClientSession", dwErrCode); } m_Connected = true; OnConnection(); return 0; } unsigned short CClientSession::GetLocalPort() { return ntohs(m_LocalAddr.sin_port); } int CClientSession::PostData(CMemNode* pMemNode) { DWORD dwNumBytes = 0; DWORD dwFlags = 0; WSABUF wsaBuf; pMemNode->SetBufType(IO_SEND); wsaBuf.buf = pMemNode->GetBufferPrt(); wsaBuf.len = pMemNode->GetUsedSize(); try { if (SOCKET_ERROR == ::WSASend(m_ConnType == 1 ? m_CliSocket : m_UdpSocket, &wsaBuf, 1, &dwNumBytes, dwFlags, pMemNode, NULL)) { DWORD dwRet = ::WSAGetLastError(); if (ERROR_IO_PENDING != dwRet) { throw CSysException("throw an exception in CClientSession-SendData", dwRet); } } } catch (...) { CloseSession(); m_MemPool->ReleaseMemNode(pMemNode); return -1; } return 0; } void CClientSession::GetSockDataLen(u_long& ulDataLen) { ioctlsocket(m_CliSocket, FIONREAD, &ulDataLen); }