声明:本文参考了发布的blog“”
Socket处理是异步非阻塞的,所以可以放心的放到主线程处理消息,并且在原作者的基本上进行了系列优化,考虑了客户端可能建立多个SOCKET,因此加入了Manager概念,与cocos2d-x进行了融合。
本文基于cocos2d-x3.0+VS2012
文件目录结构截图:
文件源码:
TCPSocket.h
1 #ifndef __CC_TCPSOCKET_H__ 2 #define __CC_TCPSOCKET_H__ 3 4 #include "cocos2d.h" 5 #include "ExtensionMacros.h" 6 #include "WorldPacket.h" 7 #ifdef WIN32 8 #include9 #include 10 #pragma comment( lib, "ws2_32.lib" ) 11 #else 12 #include 13 #include 14 #include 15 #include 16 #include 17 18 #define SOCKET int 19 #define SOCKET_ERROR -1 20 #define INVALID_SOCKET -1 21 22 #endif 23 24 NS_CC_EXT_BEGIN 25 #ifndef CHECKF 26 #define CHECKF(x) \ 27 do \ 28 { \ 29 if (!(x)) { \ 30 log_msg("CHECKF", #x, __FILE__, __LINE__); \ 31 return 0; \ 32 } \ 33 } while (0) 34 #endif 35 36 #define _MAX_MSGSIZE 16 * 1024 // 暂定一个消息最大为16k 37 #define BLOCKSECONDS 30 // INIT函数阻塞时间 38 #define INBUFSIZE (64*1024) //? 具体尺寸根据剖面报告调整 接收数据的缓存 39 #define OUTBUFSIZE (8*1024) //? 具体尺寸根据剖面报告调整。 发送数据的缓存,当不超过8K时,FLUSH只需要SEND一次 40 41 class CC_DLL TCPSocket 42 { 43 public: 44 TCPSocket(void); 45 bool Create(const char* pszServerIP, int nServerPort, int tagid, int nBlockSec = BLOCKSECONDS, bool bKeepAlive = false); 46 bool SendMsg(void* pBuf, int nSize); 47 bool ReceiveMsg(void* pBuf, int& nSize); 48 bool Flush(void); 49 bool Check(void); 50 void Destroy(void); 51 SOCKET GetSocket(void) const { return m_sockClient; } 52 53 int getTagID(){ return m_tag; } 54 private: 55 bool recvFromSock(void); // 从网络中读取尽可能多的数据 56 bool hasError(); // 是否发生错误,注意,异步模式未完成非错误 57 void closeSocket(); 58 59 SOCKET m_sockClient; 60 61 // 发送数据缓冲 62 char m_bufOutput[OUTBUFSIZE]; //? 可优化为指针数组 63 int m_nOutbufLen; 64 65 // 环形缓冲区 66 char m_bufInput[INBUFSIZE]; 67 int m_nInbufLen; 68 int m_nInbufStart; // INBUF使用循环式队列,该变量为队列起点,0 - (SIZE-1) 69 int m_tag; 70 }; 71 72 typedef std::function ProAllFunc; // 接收所有协议,自行处理,@socket标识,@协议头,@数据包,返回是否分发 73 typedef std::function ProFunc; // 接收单个协议,@socket标识,@数据包 74 typedef std::function sckFunc; // 连接成功/断开事件 75 76 #define SCT_CALLBACK_1(func, _Object) std::bind(&func,_Object, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) 77 #define SCT_CALLBACK_2(func, _Object) std::bind(&func,_Object, std::placeholders::_1, std::placeholders::_2) 78 #define SCT_CALLBACK_3(func, _Object) std::bind(&func,_Object, std::placeholders::_1) 79 // 创建SOCKET管理器 80 #define CREATE_TCPSOCKETMGR(pNode) pNode->addChild(new TCPSocketManager(), 0) 81 82 class CC_DLL TCPSocketManager : 83 public Node 84 { 85 public: 86 TCPSocketManager() 87 { 88 assert(!mSingleton); 89 this->mSingleton = this; 90 // 开启update 91 scheduleUpdate(); 92 }; 93 ~TCPSocketManager(){}; 94 // 创建socket并添加到管理器 95 TCPSocket *createSocket(const char* pszServerIP, // IP地址 96 int nServerPort, // 端口 97 int _tag, // 标识ID 98 int nBlockSec = BLOCKSECONDS, // 阻塞时间ms 99 bool bKeepAlive = false);100 // 注册协议包101 void register_process(const uint16 &entry, ProFunc callback);102 // 注册接收所有协议103 void register_all_process(ProAllFunc callback){ _pProcess = callback; }104 // 注册socket连接成功事件105 void register_connect(sckFunc callback){ _pOnConnect = callback; }106 // 注册socket断线事件107 void register_disconnect(sckFunc callback){ _OnDisconnect = callback; }108 109 // 单独添加socket到管理器110 bool addSocket(TCPSocket *pSocket);111 // 删除socket112 bool removeSocket(int _tag);113 // 断开socket114 void disconnect(int _tag);115 // 获取socket116 TCPSocket *GetSocket(int _tag);117 // 发送消息118 bool SendPacket(int _tag, WorldPacket *packet);119 120 void update(float delta);121 122 static TCPSocketManager &getSingleton(){ assert(mSingleton); return *mSingleton;}123 124 private: 125 ProAllFunc _pProcess;126 sckFunc _pOnConnect;127 sckFunc _OnDisconnect;128 std::list m_lstSocket;129 std::map _mapProcess;130 static TCPSocketManager * mSingleton;131 };132 133 #define sSocketMgr TCPSocketManager::getSingleton()134 NS_CC_EXT_END135 136 #endif //__CC_TCPSOCKET_H__
TCPSocket.cpp
#include "TCPSocket.h"#include "support/zip_support/unzip.h"NS_CC_EXT_BEGINTCPSocket::TCPSocket(){ // 初始化 memset(m_bufOutput, 0, sizeof(m_bufOutput)); memset(m_bufInput, 0, sizeof(m_bufInput));}void TCPSocket::closeSocket(){#ifdef WIN32 closesocket(m_sockClient); WSACleanup();#else close(m_sockClient);#endif}bool TCPSocket::Create(const char* pszServerIP, int nServerPort, int tagid, int nBlockSec, bool bKeepAlive /*= FALSE*/){ // 检查参数 if(pszServerIP == 0 || strlen(pszServerIP) > 15) { return false; }#ifdef WIN32 WSADATA wsaData; WORD version = MAKEWORD(2, 0); int ret = WSAStartup(version, &wsaData);//win sock start up if (ret != 0) { return false; }#endif // 创建主套接字 m_sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(m_sockClient == INVALID_SOCKET) { closeSocket(); return false; } // 设置SOCKET为KEEPALIVE if(bKeepAlive) { int optval=1; if(setsockopt(m_sockClient, SOL_SOCKET, SO_KEEPALIVE, (char *) &optval, sizeof(optval))) { closeSocket(); return false; } }#ifdef WIN32 DWORD nMode = 1; int nRes = ioctlsocket(m_sockClient, FIONBIO, &nMode); if (nRes == SOCKET_ERROR) { closeSocket(); return false; }#else // 设置为非阻塞方式 fcntl(m_sockClient, F_SETFL, O_NONBLOCK);#endif unsigned long serveraddr = inet_addr(pszServerIP); if(serveraddr == INADDR_NONE) // 检查IP地址格式错误 { closeSocket(); return false; } sockaddr_in addr_in; memset((void *)&addr_in, 0, sizeof(addr_in)); addr_in.sin_family = AF_INET; addr_in.sin_port = htons(nServerPort); addr_in.sin_addr.s_addr = serveraddr; if(connect(m_sockClient, (sockaddr *)&addr_in, sizeof(addr_in)) == SOCKET_ERROR) { if (hasError()) { closeSocket(); return false; } else // WSAWOLDBLOCK { timeval timeout; timeout.tv_sec = nBlockSec; timeout.tv_usec = 0; fd_set writeset, exceptset; FD_ZERO(&writeset); FD_ZERO(&exceptset); FD_SET(m_sockClient, &writeset); FD_SET(m_sockClient, &exceptset); int ret = select(FD_SETSIZE, NULL, &writeset, &exceptset, &timeout); if (ret == 0 || ret < 0) { closeSocket(); return false; } else // ret > 0 { ret = FD_ISSET(m_sockClient, &exceptset); if(ret) // or (!FD_ISSET(m_sockClient, &writeset) { closeSocket(); return false; } } } } m_nInbufLen = 0; m_nInbufStart = 0; m_nOutbufLen = 0; struct linger so_linger; so_linger.l_onoff = 1; so_linger.l_linger = 500; setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger)); m_tag = tagid; return true;}bool TCPSocket::SendMsg(void* pBuf, int nSize){ if(pBuf == 0 || nSize <= 0) { return false; } if (m_sockClient == INVALID_SOCKET) { return false; } // 检查通讯消息包长度 int packsize = 0; packsize = nSize; // 检测BUF溢出 if(m_nOutbufLen + nSize > OUTBUFSIZE) { // 立即发送OUTBUF中的数据,以清空OUTBUF。 Flush(); if(m_nOutbufLen + nSize > OUTBUFSIZE) { // 出错了 Destroy(); return false; } } // 数据添加到BUF尾 memcpy(m_bufOutput + m_nOutbufLen, pBuf, nSize); m_nOutbufLen += nSize; return true;}bool TCPSocket::ReceiveMsg(void* pBuf, int& nSize){ //检查参数 if(pBuf == NULL || nSize <= 0) { return false; } if (m_sockClient == INVALID_SOCKET) { return false; } // 检查是否有一个消息(小于2则无法获取到消息长度) if(m_nInbufLen < 2) { // 如果没有请求成功 或者 如果没有数据则直接返回 if(!recvFromSock() || m_nInbufLen < 2) { // 这个m_nInbufLen更新了 return false; } } // 计算要拷贝的消息的大小(一个消息,大小为整个消息的第一个16字节),因为环形缓冲区,所以要分开计算 int packsize = (unsigned char)m_bufInput[m_nInbufStart+2] + (unsigned char)m_bufInput[(m_nInbufStart + 3) % INBUFSIZE] * 256; // 注意字节序,高位+低位 // 检测消息包尺寸错误 暂定最大16k if (packsize <= 0 || packsize > _MAX_MSGSIZE) { m_nInbufLen = 0; // 直接清空INBUF m_nInbufStart = 0; return false; } // 检查消息是否完整(如果将要拷贝的消息大于此时缓冲区数据长度,需要再次请求接收剩余数据) if (packsize > m_nInbufLen) { // 如果没有请求成功 或者 依然无法获取到完整的数据包 则返回,直到取得完整包 if (!recvFromSock() || packsize > m_nInbufLen) { // 这个m_nInbufLen已更新 return false; } } // 复制出一个消息 if(m_nInbufStart + packsize > INBUFSIZE) { // 如果一个消息有回卷(被拆成两份在环形缓冲区的头尾) // 先拷贝环形缓冲区末尾的数据 int copylen = INBUFSIZE - m_nInbufStart; memcpy(pBuf, m_bufInput + m_nInbufStart, copylen); // 再拷贝环形缓冲区头部的剩余部分 memcpy((unsigned char *)pBuf + copylen, m_bufInput, packsize - copylen); nSize = packsize; } else { // 消息没有回卷,可以一次拷贝出去 memcpy(pBuf, m_bufInput + m_nInbufStart, packsize); nSize = packsize; } // 重新计算环形缓冲区头部位置 m_nInbufStart = (m_nInbufStart + packsize) % INBUFSIZE; m_nInbufLen -= packsize; return true;}bool TCPSocket::hasError(){#ifdef WIN32 int err = WSAGetLastError(); if(err != WSAEWOULDBLOCK) {#else int err = errno; if(err != EINPROGRESS && err != EAGAIN) {#endif return true; } return false;}// 从网络中读取尽可能多的数据,实际向服务器请求数据的地方bool TCPSocket::recvFromSock(void){ if (m_nInbufLen >= INBUFSIZE || m_sockClient == INVALID_SOCKET) { return false; } // 接收第一段数据 int savelen, savepos; // 数据要保存的长度和位置 if(m_nInbufStart + m_nInbufLen < INBUFSIZE) { // INBUF中的剩余空间有回绕 savelen = INBUFSIZE - (m_nInbufStart + m_nInbufLen); // 后部空间长度,最大接收数据的长度 } else { savelen = INBUFSIZE - m_nInbufLen; } // 缓冲区数据的末尾 savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE; //CHECKF(savepos + savelen <= INBUFSIZE); int inlen = recv(m_sockClient, m_bufInput + savepos, savelen, 0); if(inlen > 0) { // 有接收到数据 m_nInbufLen += inlen; if (m_nInbufLen > INBUFSIZE) { return false; } // 接收第二段数据(一次接收没有完成,接收第二段数据) if(inlen == savelen && m_nInbufLen < INBUFSIZE) { int savelen = INBUFSIZE - m_nInbufLen; int savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE; //CHECKF(savepos + savelen <= INBUFSIZE); inlen = recv(m_sockClient, m_bufInput + savepos, savelen, 0); if(inlen > 0) { m_nInbufLen += inlen; if (m_nInbufLen > INBUFSIZE) { return false; } } else if(inlen == 0) { Destroy(); return false; } else { // 连接已断开或者错误(包括阻塞) if (hasError()) { Destroy(); return false; } } } } else if(inlen == 0) { Destroy(); return false; } else { // 连接已断开或者错误(包括阻塞) if (hasError()) { Destroy(); return false; } } return true;}bool TCPSocket::Flush(void) //? 如果 OUTBUF > SENDBUF 则需要多次SEND(){ if (m_sockClient == INVALID_SOCKET) { return false; } if(m_nOutbufLen <= 0) { return true; } // 发送一段数据 int outsize; outsize = send(m_sockClient, m_bufOutput, m_nOutbufLen, 0); if(outsize > 0) { // 删除已发送的部分 if(m_nOutbufLen - outsize > 0) { memcpy(m_bufOutput, m_bufOutput + outsize, m_nOutbufLen - outsize); } m_nOutbufLen -= outsize; if (m_nOutbufLen < 0) { return false; } } else { if (hasError()) { Destroy(); return false; } } return true;}bool TCPSocket::Check(void){ // 检查状态 if (m_sockClient == INVALID_SOCKET) { return false; } char buf[1]; int ret = recv(m_sockClient, buf, 1, MSG_PEEK); if(ret == 0) { Destroy(); return false; } else if(ret < 0) { if (hasError()) { Destroy(); return false; } else { // 阻塞 return true; } } else { // 有数据 return true; } return true;}void TCPSocket::Destroy(void){ // 关闭 struct linger so_linger; so_linger.l_onoff = 1; so_linger.l_linger = 500; int ret = setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger)); closeSocket(); m_sockClient = INVALID_SOCKET; m_nInbufLen = 0; m_nInbufStart = 0; m_nOutbufLen = 0; memset(m_bufOutput, 0, sizeof(m_bufOutput)); memset(m_bufInput, 0, sizeof(m_bufInput));}TCPSocketManager *TCPSocketManager::mSingleton = 0;TCPSocket *TCPSocketManager::createSocket(const char* pszServerIP, // IP地址 int nServerPort, // 端口 int _tag, // 标识ID int nBlockSec, // 阻塞时间ms bool bKeepAlive){ TCPSocket *pSocket = new TCPSocket(); if (pSocket->Create(pszServerIP, nServerPort, _tag, nBlockSec, bKeepAlive)) { assert(addSocket(pSocket)); if (_pOnConnect){ _pOnConnect(_tag); } return pSocket; } delete pSocket; return NULL;}bool TCPSocketManager::addSocket(TCPSocket *pSocket){ std::list::iterator iter, enditer = m_lstSocket.end(); for (iter = m_lstSocket.begin(); iter != enditer; ++ iter) { if ((*iter)->GetSocket() == pSocket->GetSocket()) return false; } m_lstSocket.push_back(pSocket); return true;}// 删除socketbool TCPSocketManager::removeSocket(int _tag){ std::list ::iterator iter, enditer = m_lstSocket.end(); for (iter = m_lstSocket.begin(); iter != enditer; ++ iter) { if ((*iter)->getTagID() == _tag) { (*iter)->Destroy(); m_lstSocket.erase(iter); return true; } } return false;}TCPSocket *TCPSocketManager::GetSocket(int _tag){ std::list ::iterator iter, enditer = m_lstSocket.end(); for (iter = m_lstSocket.begin(); iter != enditer; ++ iter) { if ((*iter)->getTagID() == _tag) { return *iter; } } return NULL;}void TCPSocketManager::update(float delta){ std::list ::iterator iter, enditer = m_lstSocket.end(); for (iter = m_lstSocket.begin(); iter != enditer; ++ iter) { TCPSocket *pSocket = *iter; int _tag = pSocket->getTagID(); if (!pSocket->Check()) { // 掉线了 _OnDisconnect(_tag); m_lstSocket.erase(iter); break; } while (true) { char buffer[_MAX_MSGSIZE] = { 0}; int nSize = sizeof(buffer); char *pbufMsg = buffer; if (!pSocket->ReceiveMsg(pbufMsg, nSize)) break; WorldPacket packet; uint16 _cmd, _length; packet.Write((uint8*)pbufMsg, nSize); packet >> _cmd >> _length; if (_cmd & 0x8000) { Byte uncompr[1024] = { 0}; uLong uncomprLen; _cmd &= 0x7fff; uncompress(uncompr, &uncomprLen, packet.contents()+4, packet.size()-4); } if (_pProcess == 0 || _pProcess(pSocket->getTagID(), _cmd, packet)) { // 分发数据 std::map ::iterator mapi = _mapProcess.find(_cmd); if (mapi == _mapProcess.end()) continue; mapi->second(pSocket->getTagID(), packet); } } }}void TCPSocketManager::register_process(const uint16 &entry, ProFunc callback){ _mapProcess[entry] = callback;}bool TCPSocketManager::SendPacket(int _tag, WorldPacket *packet){ std::list ::iterator iter, enditer = m_lstSocket.end(); for (iter = m_lstSocket.begin(); iter != enditer; ++ iter) { if ((*iter)->getTagID() == _tag) { (*iter)->SendMsg((void *)packet->contents(), packet->size()); return (*iter)->Flush(); } } return false;}void TCPSocketManager::disconnect(int _tag){ std::list ::iterator iter, enditer = m_lstSocket.end(); for (iter = m_lstSocket.begin(); iter != enditer; ++ iter) { if ((*iter)->getTagID() == _tag) { (*iter)->Destroy(); if (_OnDisconnect){ _OnDisconnect(_tag); } break; } }}NS_CC_EXT_END
ByteBuffer.h (读写数据包)
1 /**************************************************************************** 2 * 3 * ByteBuffer Class 4 * 5 */ 6 7 #ifndef _BYTEBUFFER_H 8 #define _BYTEBUFFER_H 9 10 #include "Common.h" 11 //#include "Vector3.h" 12 13 class ByteBuffer 14 { 15 #define DEFAULT_SIZE 0x1000 16 #define DEFAULT_INCREASE_SIZE 200 17 uint8 * m_buffer; 18 size_t m_readPos; 19 size_t m_writePos; 20 uint32 m_buffersize; 21 22 public: 23 /** Creates a bytebuffer with the default size 24 */ 25 ByteBuffer() 26 { 27 m_buffer =0; 28 m_readPos = m_writePos = 0; 29 m_buffersize = 0; 30 reserve(DEFAULT_SIZE); 31 } 32 33 /** Creates a bytebuffer with the specified size 34 */ 35 ByteBuffer(size_t res) 36 { 37 m_buffer =0; 38 m_readPos = m_writePos = 0; 39 m_buffersize = 0; 40 reserve(res); 41 } 42 43 /** Frees the allocated buffer 44 */ 45 ~ByteBuffer() 46 { 47 free(m_buffer); 48 } 49 50 51 /** Allocates/reallocates buffer with specified size. 52 */ 53 void reserve(size_t res) 54 { 55 if(m_buffer) 56 m_buffer = (uint8*)realloc(m_buffer, res); 57 else 58 m_buffer = (uint8*)malloc(res); 59 60 m_buffersize = res; 61 } 62 63 64 /** Resets read/write indexes 65 */ 66 inline void clear() 67 { 68 m_readPos = m_writePos = 0; 69 } 70 71 /** Sets write position 72 */ 73 inline void resize(size_t size) 74 { 75 m_writePos = size; 76 } 77 78 /** Returns the buffer pointer 79 */ 80 inline const uint8 * contents() 81 { 82 return m_buffer; 83 } 84 85 86 /** Gets the buffer size. 87 */ 88 uint32 GetBufferSize() { return m_writePos; } 89 90 /** Reads sizeof(T) bytes from the buffer 91 * @return the bytes read 92 */ 93 template94 T Read() 95 { 96 if(m_readPos + sizeof(T) > m_writePos) 97 return (T)0; 98 T ret = *(T*)&m_buffer[m_readPos]; 99 m_readPos += sizeof(T);100 return ret;101 }102 103 void skip(size_t len)104 {105 if(m_readPos + len > m_writePos)106 len = (m_writePos - m_readPos);107 m_readPos += len;108 }109 110 /** Reads x bytes from the buffer111 */112 void read(uint8 * buffer, size_t len)113 {114 if(m_readPos + len > m_writePos)115 len = (m_writePos - m_readPos);116 117 memcpy(buffer, &m_buffer[m_readPos], len);118 m_readPos += len;119 }120 121 /** Writes sizeof(T) bytes to the buffer, while checking for overflows.122 * @param T data The data to be written123 */124 template 125 void Write(const T & data)126 {127 size_t new_size = m_writePos + sizeof(T);128 if(new_size > m_buffersize)129 {130 new_size = (new_size / DEFAULT_INCREASE_SIZE + 1) * DEFAULT_INCREASE_SIZE;131 reserve(new_size);132 }133 134 *(T*)&m_buffer[m_writePos] = data;135 m_writePos += sizeof(T);136 }137 138 /** writes x bytes to the buffer, while checking for overflows139 * @param ptr the data to be written140 * @param size byte count141 */142 void Write(const uint8 * data, size_t size)143 {144 size_t new_size = m_writePos + size;145 if(new_size > m_buffersize)146 {147 new_size = (new_size / DEFAULT_INCREASE_SIZE + 1) * DEFAULT_INCREASE_SIZE;148 reserve(new_size);149 }150 151 memcpy(&m_buffer[m_writePos], data, size);152 m_writePos += size;153 }154 155 /** Ensures the buffer is big enough to fit the specified number of bytes.156 * @param bytes number of bytes to fit157 */158 inline void EnsureBufferSize(uint32 Bytes)159 {160 size_t new_size = m_writePos + Bytes;161 if(new_size > m_buffersize)162 {163 new_size = (new_size / DEFAULT_INCREASE_SIZE + 1) * DEFAULT_INCREASE_SIZE;164 reserve(new_size);165 }166 167 }168 169 /** These are the default read/write operators.170 */171 #define DEFINE_BUFFER_READ_OPERATOR(type) void operator >> (type& dest) { dest = Read (); }172 #define DEFINE_BUFFER_WRITE_OPERATOR(type) void operator << (const type src) { Write (src); }173 174 /** Fast read/write operators without using the templated read/write functions.175 */176 #define DEFINE_FAST_READ_OPERATOR(type, size) ByteBuffer& operator >> (type& dest) { if(m_readPos + size > m_writePos) { dest = (type)0; return *this; } else { dest = *(type*)&m_buffer[m_readPos]; m_readPos += size; return *this; } }177 #define DEFINE_FAST_WRITE_OPERATOR(type, size) ByteBuffer& operator << (const type src) { if(m_writePos + size > m_buffersize) { reserve(m_buffersize + DEFAULT_INCREASE_SIZE); } *(type*)&m_buffer[m_writePos] = src; m_writePos += size; return *this; }178 179 /** Integer/float r/w operators180 */181 DEFINE_FAST_READ_OPERATOR(uint64, 8);182 DEFINE_FAST_READ_OPERATOR(uint32, 4);183 DEFINE_FAST_READ_OPERATOR(uint16, 2);184 DEFINE_FAST_READ_OPERATOR(uint8, 1);185 DEFINE_FAST_READ_OPERATOR(int64, 8);186 DEFINE_FAST_READ_OPERATOR(int32, 4);187 DEFINE_FAST_READ_OPERATOR(int16, 2);188 DEFINE_FAST_READ_OPERATOR(int8, 1);189 DEFINE_FAST_READ_OPERATOR(float, 4);190 DEFINE_FAST_READ_OPERATOR(double, 8);191 192 DEFINE_FAST_WRITE_OPERATOR(uint64, 8);193 DEFINE_FAST_WRITE_OPERATOR(uint32, 4);194 DEFINE_FAST_WRITE_OPERATOR(uint16, 2);195 DEFINE_FAST_WRITE_OPERATOR(uint8, 1);196 DEFINE_FAST_WRITE_OPERATOR(int64, 8);197 DEFINE_FAST_WRITE_OPERATOR(int32, 4);198 DEFINE_FAST_WRITE_OPERATOR(int16, 2);199 DEFINE_FAST_WRITE_OPERATOR(int8, 1);200 DEFINE_FAST_WRITE_OPERATOR(float, 4);201 DEFINE_FAST_WRITE_OPERATOR(double, 8);202 203 /** boolean (1-byte) read/write operators204 */205 DEFINE_FAST_WRITE_OPERATOR(bool, 1);206 ByteBuffer& operator >> (bool & dst) { dst = (Read () > 0 ? true : false); return *this; }207 208 /** string (null-terminated) operators209 */210 ByteBuffer& operator << (const std::string & value) { EnsureBufferSize(value.length() + 1); memcpy(&m_buffer[m_writePos], value.c_str(), value.length()+1); m_writePos += (value.length() + 1); return *this; }211 ByteBuffer& operator >> (std::string & dest)212 {213 dest.clear();214 char c;215 for(;;)216 {217 c = Read ();218 if(c == 0) break;219 dest += c;220 }221 return *this;222 }223 224 /** Gets the write position225 * @return buffer size226 */227 inline size_t size() { return m_writePos; }228 229 /** read/write position setting/getting230 */231 inline size_t rpos() { return m_readPos; }232 inline size_t wpos() { return m_writePos; }233 inline void rpos(size_t p) { assert(p <= m_writePos); m_readPos = p; }234 inline void wpos(size_t p) { assert(p <= m_buffersize); m_writePos = p; }235 236 template size_t writeVector(std::vector &v)237 {238 for (typename std::vector ::const_iterator i = v.begin(); i != v.end(); i++) {239 Write (*i);240 }241 return v.size();242 243 }244 template size_t readVector(size_t vsize, std::vector &v)245 {246 247 v.clear();248 while(vsize--) {249 T t = Read ();250 v.push_back(t);251 }252 return v.size();253 }254 255 template size_t writeList(std::list &v)256 {257 for (typename std::list ::const_iterator i = v.begin(); i != v.end(); i++) {258 Write (*i);259 }260 return v.size();261 262 }263 template size_t readList(size_t vsize, std::list &v)264 {265 266 v.clear();267 while(vsize--) {268 T t = Read ();269 v.push_back(t);270 }271 return v.size();272 }273 274 template size_t writeMap(const std::map &m)275 {276 for (typename std::map ::const_iterator i = m.begin(); i != m.end(); i++) {277 Write (i->first);278 Write (i->second);279 }280 return m.size();281 }282 283 template size_t readMap(size_t msize, std::map &m)284 {285 m.clear();286 while(msize--) {287 K k = Read ();288 V v = Read ();289 m.insert(make_pair(k, v));290 }291 return m.size();292 }293 294 };295 296 ///297 ///298 ///299 300 template ByteBuffer &operator<<(ByteBuffer &b, const std::vector & v)301 {302 b << (uint32)v.size();303 for (typename std::vector ::const_iterator i = v.begin(); i != v.end(); i++) {304 b << *i;305 }306 return b;307 }308 309 template ByteBuffer &operator>>(ByteBuffer &b, std::vector &v)310 {311 uint32 vsize;312 b >> vsize;313 v.clear();314 while(vsize--) {315 T t;316 b >> t;317 v.push_back(t);318 }319 return b;320 }321 322 template ByteBuffer &operator<<(ByteBuffer &b, const std::list & v)323 {324 b << (uint32)v.size();325 for (typename std::list ::const_iterator i = v.begin(); i != v.end(); i++) {326 b << *i;327 }328 return b;329 }330 331 template ByteBuffer &operator>>(ByteBuffer &b, std::list &v)332 {333 uint32 vsize;334 b >> vsize;335 v.clear();336 while(vsize--) {337 T t;338 b >> t;339 v.push_back(t);340 }341 return b;342 }343 344 template ByteBuffer &operator<<(ByteBuffer &b, const std::map &m)345 {346 b << (uint32)m.size();347 for (typename std::map ::const_iterator i = m.begin(); i != m.end(); i++) {348 b << i->first << i->second;349 }350 return b;351 }352 353 template ByteBuffer &operator>>(ByteBuffer &b, std::map &m)354 {355 uint32 msize;356 b >> msize;357 m.clear();358 while(msize--) {359 K k;360 V v;361 b >> k >> v;362 m.insert(make_pair(k, v));363 }364 return b;365 }366 367 #endif
WorldPacket.h (读写扩展类,协议前2字节表示协议包,其次2字节表示数据大小)
1 #ifndef WGSERVER_WORLDPACKET_H 2 #define WGSERVER_WORLDPACKET_H 3 4 5 #include "ByteBuffer.h" 6 7 8 class WorldPacket : public ByteBuffer 9 { 10 public: 11 __inline WorldPacket() : ByteBuffer(), m_opcode(0) { } 12 __inline WorldPacket(uint16 opcode, size_t res) : ByteBuffer(res), m_opcode(opcode) {} 13 __inline WorldPacket(size_t res) : ByteBuffer(res), m_opcode(0) { } 14 __inline WorldPacket(const WorldPacket &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode) {} 15 16 //! Clear packet and set opcode all in one mighty blow 17 __inline void Initialize(uint16 opcode ) 18 { 19 clear(); 20 m_opcode = opcode; 21 } 22 23 __inline uint16 GetOpcode() const { return m_opcode; } 24 __inline void SetOpcode(const uint16 & opcode) { m_opcode = opcode; } 25 __inline void SetLength(const uint16 & len) { 26 uint16 * plen = (uint16 * ) &(contents()[2]); 27 *plen = len; 28 } 29 30 __inline std::string getString() 31 { 32 //std::string buff = 33 return (const char*)contents(); 34 } 35 36 template37 void SetOffset(const uint16 & offset, const T value ) { 38 T * pval = (T *) &(contents()[offset]); 39 *pval = value; 40 } 41 42 public: 43 /** 44 * @创建时间 2011-08-31 45 * @创建人 李志勇 46 * @函数作用 向数据包追加字符串 47 * @参数 48 * @packet 数据封包指针 49 * @str 追加的字符串 50 */ 51 template void AppendPacketString(std::string str) 52 { 53 T ilen = (T)str.size(); 54 *this << ilen; 55 if (ilen > 0) 56 Write((const uint8 *) str.c_str(), ilen); 57 } 58 /** 59 * @创建时间 2011-08-31 60 * @创建人 李志勇 61 * @函数作用 获取字符串 62 * @参数 63 * @packet 数据封包 64 * @返回 是否成功 65 */ 66 template bool GetPacketString(std::string &str) 67 { 68 T ilen; 69 *this >> ilen; 70 if (ilen == 0) 71 return true; 72 uint8 buf[ilen+1]; 73 uint16 plen = size(); 74 if (plen < ilen) 75 return false; 76 read(buf, ilen); 77 buf[ilen] = 0; 78 str = (char*)buf; 79 return true; 80 } 81 82 83 protected: 84 uint16 m_opcode; 85 }; 86 87 /* 88 template 89 class SERVER_DECL StackWorldPacket : public StackBuffer 90 { 91 uint16 m_opcode; 92 public: 93 __inline StackWorldPacket(uint16 opcode) : StackBuffer (), m_opcode(opcode) { } 94 95 //! Clear packet and set opcode all in one mighty blow 96 __inline void Initialize(uint16 opcode ) 97 { 98 StackBuffer ::Clear(); 99 m_opcode = opcode;100 }101 102 uint16 GetOpcode() { return m_opcode; }103 __inline void SetOpcode(uint16 opcode) { m_opcode = opcode; }104 };105 */106 107 #endif
Common.h (bytebuffer.h所需的一些定义,该文件来自“魔兽世界服务端”源码,cocos2d-x自身有个CCommon.h文件,如果把两个文件合并的话,在linux下编译会发生冲突,冲突较多,本人也没有做区分,因此建议独立出来)
1 #ifndef WGSERVER_COMMON_H 2 #define WGSERVER_COMMON_H 3 4 5 #ifdef WIN32 6 #pragma warning(disable:4996) 7 #define _CRT_SECURE_NO_DEPRECATE 1 8 #define _CRT_SECURE_COPP_OVERLOAD_STANDARD_NAMES 1 9 #pragma warning(disable:4251) // dll-interface bullshit 10 #endif 11 12 enum TimeVariables 13 { 14 TIME_SECOND = 1, 15 TIME_MINUTE = TIME_SECOND * 60, 16 TIME_HOUR = TIME_MINUTE * 60, 17 TIME_DAY = TIME_HOUR * 24, 18 TIME_MONTH = TIME_DAY * 30, 19 TIME_YEAR = TIME_MONTH * 12 20 }; 21 22 enum MsTimeVariables 23 { 24 MSTIME_SECOND = 1000, 25 MSTIME_MINUTE = MSTIME_SECOND * 60, 26 MSTIME_HOUR = MSTIME_MINUTE * 60, 27 MSTIME_DAY = MSTIME_HOUR * 24 28 }; 29 30 #ifdef WIN32 31 #define WGSERVER_INLINE __forceinline 32 #else 33 #define WGSERVER_INLINE inline 34 #endif 35 36 #ifdef HAVE_CONFIG_H 37 # include38 #endif 39 40 41 /* Define this if you're using a big-endian machine */ 42 #ifdef USING_BIG_ENDIAN 43 #include 44 #define bswap_16(x) NXSwapShort(x) 45 #define bswap_32(x) NXSwapInt(x) 46 #define bswap_64(x) NXSwapLongLong(x) 47 #endif 48 49 #include 50 #include 51 #include 52 #include 53 #include 54 #include 55 #include 56 //#include 57 58 59 #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 ) 60 # define WIN32_LEAN_AND_MEAN 61 //# define _WIN32_WINNT 0x0500 62 # define NOMINMAX 63 # include 64 #else 65 # include 66 # define MAX_PATH 1024 67 #endif 68 69 #ifdef min 70 #undef min 71 #endif 72 73 #ifdef max 74 #undef max 75 #endif 76 77 #ifdef CONFIG_USE_SELECT 78 #undef FD_SETSIZE 79 #define FD_SETSIZE 2048 80 #endif 81 82 #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 ) 83 #include 84 #include 85 #else 86 #include 87 #include 88 #include 89 #include 90 #include 91 #include 92 #include 93 #include 94 #include 95 #endif 96 97 // current platform and compiler 98 #define PLATFORM_WIN32 0 99 #define PLATFORM_UNIX 1100 #define PLATFORM_APPLE 2101 102 #define UNIX_FLAVOUR_LINUX 1103 #define UNIX_FLAVOUR_BSD 2104 #define UNIX_FLAVOUR_OTHER 3105 #define UNIX_FLAVOUR_OSX 4106 107 #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )108 # define PLATFORM PLATFORM_WIN32109 #elif defined( __APPLE_CC__ )110 # define PLATFORM PLATFORM_APPLE111 #else112 # define PLATFORM PLATFORM_UNIX113 #endif114 115 #define COMPILER_MICROSOFT 0116 #define COMPILER_GNU 1117 #define COMPILER_BORLAND 2118 119 #ifdef _MSC_VER120 # define COMPILER COMPILER_MICROSOFT121 #elif defined( __BORLANDC__ )122 # define COMPILER COMPILER_BORLAND123 #elif defined( __GNUC__ )124 # define COMPILER COMPILER_GNU125 #else126 # pragma error "FATAL ERROR: Unknown compiler."127 #endif128 129 #if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE130 #ifdef HAVE_DARWIN131 #define PLATFORM_TEXT "MacOSX"132 #define UNIX_FLAVOUR UNIX_FLAVOUR_OSX133 #else134 #ifdef USE_KQUEUE135 #define PLATFORM_TEXT "FreeBSD"136 #define UNIX_FLAVOUR UNIX_FLAVOUR_BSD137 #else138 #define PLATFORM_TEXT "Linux"139 #define UNIX_FLAVOUR UNIX_FLAVOUR_LINUX140 #endif141 #endif142 #endif143 144 #if PLATFORM == PLATFORM_WIN32145 #define PLATFORM_TEXT "Win32"146 #endif147 148 #ifdef _DEBUG149 #define CONFIG "Debug"150 #else151 #define CONFIG "Release"152 #endif153 154 #ifdef USING_BIG_ENDIAN155 #define ARCH "PPC"156 #else157 #ifdef X64158 #define ARCH "X64"159 #else160 #define ARCH "X86"161 #endif162 #endif163 164 /*#if COMPILER == COMPILER_MICROSOFT165 # pragma warning( disable : 4267 ) // conversion from 'size_t' to 'int', possible loss of data166 # pragma warning( disable : 4311 ) // 'type cast': pointer truncation from HMODULE to uint32167 # pragma warning( disable : 4786 ) // identifier was truncated to '255' characters in the debug information168 # pragma warning( disable : 4146 )169 # pragma warning( disable : 4800 )170 #endif*/171 172 #if PLATFORM == PLATFORM_WIN32173 #define STRCASECMP stricmp174 #else175 #define STRCASECMP strcasecmp176 #endif177 178 #if PLATFORM == PLATFORM_WIN32179 #define ASYNC_NET180 #endif181 182 #ifdef USE_EPOLL183 #define CONFIG_USE_EPOLL184 #endif185 #ifdef USE_KQUEUE186 #define CONFIG_USE_KQUEUE187 #endif188 #ifdef USE_SELECT189 #define CONFIG_USE_SELECT190 #endif191 #ifdef USE_POLL192 #define CONFIG_USE_POLL193 #endif194 195 #ifdef min196 #undef min197 #endif198 199 #ifdef max200 #undef max201 #endif202 203 #include 204 #include 205 #include 206 #include
207 #include
另外,
在extensions/cocos-ext.h文件内加入
#include "network/TCPSocket.h"
在extensions/Android.mk文件内加入,使其在linux下能够编译到
network/TCPSocket.cpp \
使用例子,代码片段:
/// // 创建SOCKET管理器 CREATE_TCPSOCKETMGR(this); // 创建并添加SOCKET,参数:服务器IP,端口,自定义的SOCKET_ID标识 sSocketMgr.createSocket("192.168.0.183", 7502, 1); // 注册协议,参数:包头,回调函数 sSocketMgr.register_process(0x10, SCT_CALLBACK_2(HelloWorld::login, this)); // 注册消息截获事件,注册此事件后可以截获收到的所有消息,若回调函数返回true则本次事件会继续分发注册过的协议,返回false则不分发 sSocketMgr.register_all_process(SCT_CALLBACK_1(HelloWorld::process, this)); // 定义协议包 WorldPacket packet; packet.clear(); // 设置协议头 packet.SetOpcode(0x0010); packet << uint16(0x0010) << uint16(0)// 协议长度 << uint32(1) << uint32(0); // 加入字符串数据(uint8表示字符串长度所占字节,此处为1字节) packet.AppendPacketString(std::string("aaa:88889083:d5956683c17d7e284d33ee295b277b52")); // 设置协议长度 packet.SetLength(packet.size()); // 发送数据 sSocketMgr.SendPacket(1, &packet); ///
回调函数例子:
1 // 注册单个协议回调函数(样例),参数:SOCKET_ID标识,数据包2 void process_login(int _tag, WorldPacket & packet);3 // 注册单个协议回调函数(样例),参数:SOCKET_ID标识,协议头,数据包4 bool process_all(int _tag, int _cmd, WorldPacket & packet);5 // 断线事件6 void onDisconnect(int _tag);
取数据例子:
WorldPacket packet ; // 取整形数据uint16 opcode;uint16 len;uint32 serial;float fl; packet >> opcode;packet >> len;packet >> serial;packet >> fl; // 取字符串String oldPwd, newPwd; packet.GetPacketString(&packet, oldPwd);packet.GetPacketString (&packet, newPwd);
写得比较草,如果看不懂的,好的建议和意见可以给我留言。
如果有不同的,好的思路也可以提出来,一起探讨。。