packet_sync.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /***************************************
  2. * @file packet_sync.h
  3. * @brief TCP 数据包封装.依赖libuv,openssl.功能:接收数据,解析得到一帧后回调给用户。同步处理,接收到马上解析
  4. * @details 根据net_base.h中NetPacket的定义,对数据包进行封装。
  5. md5校验码使用openssl函数
  6. 同一线程中实时解码
  7. 长度为0的md5为:d41d8cd98f00b204e9800998ecf8427e,改为全0. 编解码时修改。
  8. //调用方法
  9. Packet packet;
  10. packet.SetPacketCB(GetPacket,&serpac);
  11. packet.Start(0x01,0x02);
  12. //socket有数据到达时,调用packet.recvdata((const unsigned char*)buf,bufsize); 只要足够一帧它会触发GetFullPacket
  13. * @author phata, wqvbjhc@gmail.com
  14. * @date 2014-05-21
  15. * @mod 2014-08-04 phata 修复解析一帧数据有误的bug
  16. 2014-11-12 phata GetUVError冲突,改为使用thread_uv.h中的
  17. ****************************************/
  18. #ifndef PACKET_SYNC_H
  19. #define PACKET_SYNC_H
  20. #include <algorithm>
  21. #include "net_base.h"
  22. #include "thread_uv.h"//for GetUVError
  23. #include <openssl\md5.h>
  24. #if defined (WIN32) || defined(_WIN32)
  25. #include <windows.h>
  26. #define ThreadSleep(ms) Sleep(ms);//睡眠ms毫秒
  27. #elif defined __linux__
  28. #include <unistd.h>
  29. #define ThreadSleep(ms) usleep((ms) * 1000)//睡眠ms毫秒
  30. #endif
  31. #ifdef _MSC_VER
  32. #pragma comment(lib,"libeay32.lib")
  33. #pragma comment(lib,"ws2_32.lib")
  34. #pragma comment(lib,"libuv.lib")
  35. #pragma comment(lib, "IPHLPAPI.lib")
  36. #pragma comment(lib, "Psapi.lib")
  37. #pragma comment(lib, "Userenv.lib")
  38. #endif
  39. typedef void (*GetFullPacket)(const NetPacket& packethead, const unsigned char* packetdata, void* userdata);
  40. #ifndef BUFFER_SIZE
  41. #define BUFFER_SIZE (1024*10)
  42. #endif
  43. class PacketSync
  44. {
  45. public:
  46. PacketSync(): packet_cb_(NULL), packetcb_userdata_(NULL) {
  47. thread_readdata = uv_buf_init((char*)malloc(BUFFER_SIZE), BUFFER_SIZE); //负责从circulebuffer_读取数据
  48. thread_packetdata = uv_buf_init((char*)malloc(BUFFER_SIZE), BUFFER_SIZE); //负责从circulebuffer_读取packet 中data部分
  49. truepacketlen = 0;//readdata有效数据长度
  50. headpos = -1;//找到头位置
  51. headpt = NULL;//找到头位置
  52. parsetype = PARSE_NOTHING;
  53. getdatalen = 0;
  54. }
  55. virtual ~PacketSync() {
  56. free(thread_readdata.base);
  57. free(thread_packetdata.base);
  58. }
  59. bool Start(char packhead, char packtail) {
  60. HEAD = packhead;
  61. TAIL = packtail;
  62. return true;
  63. }
  64. public:
  65. void recvdata(const unsigned char* data, int len) { //接收到数据,把数据保存在circulebuffer_
  66. int iret = 0;
  67. while (iret < len || truepacketlen >= NET_PACKAGE_HEADLEN + 2) {
  68. if (PARSE_NOTHING == parsetype) {//未解析出head
  69. if (thread_readdata.len - truepacketlen >= len - iret) {
  70. memcpy(thread_readdata.base + truepacketlen, data + iret, len - iret);
  71. truepacketlen += len - iret;
  72. iret = len;
  73. } else {
  74. memcpy(thread_readdata.base + truepacketlen, data + iret, thread_readdata.len - truepacketlen);
  75. iret += thread_readdata.len - truepacketlen;
  76. truepacketlen = thread_readdata.len;
  77. }
  78. headpt = (char*)memchr(thread_readdata.base, HEAD, truepacketlen);
  79. if (!headpt) {//1
  80. fprintf(stdout, "读取%d数据,找不到包头\n", truepacketlen);
  81. truepacketlen = 0;//标记thread_readdata里的数据为无效
  82. continue;
  83. }
  84. headpos = headpt - thread_readdata.base;
  85. if (truepacketlen - headpos - 1 < NET_PACKAGE_HEADLEN) { //2.2
  86. if (headpos != 0) {
  87. fprintf(stdout, "读取%d数据,找到包头,位于%d,数据不够解析帧头,先缓存\n", truepacketlen, headpos);
  88. memmove(thread_readdata.base, thread_readdata.base + headpos, truepacketlen - headpos);
  89. truepacketlen -= headpos;
  90. }
  91. continue;
  92. }
  93. //得帧头
  94. headpt = &thread_readdata.base[headpos + 1];
  95. CharToNetPacket((const unsigned char*)(headpt), theNexPacket);
  96. if (theNexPacket.header != HEAD || theNexPacket.tail != TAIL || theNexPacket.datalen < 0) {//帧头数据不合法(帧长允许为0)
  97. fprintf(stdout, "读取%d数据,包头位于%d. 帧数据不合法(head:%02x,tail:%02x,datalen:%d)\n",
  98. truepacketlen, headpos, theNexPacket.header, theNexPacket.tail, theNexPacket.datalen);
  99. memmove(thread_readdata.base, thread_readdata.base + headpos + 1, truepacketlen - headpos - 1); //2.4
  100. truepacketlen -= headpos + 1;
  101. continue;
  102. }
  103. parsetype = PARSE_HEAD;
  104. //得帧数据
  105. if (thread_packetdata.len < (size_t)theNexPacket.datalen + 1) { //包含最后的tail
  106. thread_packetdata.base = (char*)realloc(thread_packetdata.base, theNexPacket.datalen + 1);
  107. thread_packetdata.len = theNexPacket.datalen + 1;
  108. }
  109. getdatalen = (std::min)((int)(truepacketlen - headpos - 1 - NET_PACKAGE_HEADLEN), (int)(theNexPacket.datalen + 1));
  110. //先从thread_readdata中取
  111. if (getdatalen > 0) {
  112. memcpy(thread_packetdata.base, thread_readdata.base + headpos + 1 + NET_PACKAGE_HEADLEN, getdatalen);
  113. }
  114. }
  115. //解析出head,在接收data
  116. if (getdatalen < theNexPacket.datalen + 1) {
  117. if (getdatalen + (len - iret) < theNexPacket.datalen + 1) {
  118. memcpy(thread_packetdata.base + getdatalen, data + iret, len - iret);
  119. getdatalen += len - iret;
  120. iret = len;
  121. return;//等待下一轮的读取
  122. } else {
  123. memcpy(thread_packetdata.base + getdatalen, data + iret, theNexPacket.datalen + 1 - getdatalen);
  124. iret += theNexPacket.datalen + 1 - getdatalen;
  125. getdatalen = theNexPacket.datalen + 1;
  126. }
  127. }
  128. //检测校验码与最后一位
  129. if (thread_packetdata.base[theNexPacket.datalen] != TAIL) {
  130. fprintf(stdout, "包数据长%d, 包尾数据不合法(tail:%02x)\n", theNexPacket.datalen,
  131. (unsigned char)(thread_packetdata.base[theNexPacket.datalen]));
  132. if (truepacketlen - headpos - 1 - NET_PACKAGE_HEADLEN >= theNexPacket.datalen + 1) {//thread_readdata数据足够
  133. memmove(thread_readdata.base, thread_readdata.base + headpos + 1, truepacketlen - headpos - 1); //2.4
  134. truepacketlen -= headpos + 1;
  135. } else {//thread_readdata数据不足
  136. if (thread_readdata.len < NET_PACKAGE_HEADLEN + theNexPacket.datalen + 1) {//包含最后的tail
  137. thread_readdata.base = (char*)realloc(thread_readdata.base, NET_PACKAGE_HEADLEN + theNexPacket.datalen + 1);
  138. thread_readdata.len = NET_PACKAGE_HEADLEN + theNexPacket.datalen + 1;
  139. }
  140. memmove(thread_readdata.base, thread_readdata.base + headpos + 1, NET_PACKAGE_HEADLEN); //2.4
  141. truepacketlen = NET_PACKAGE_HEADLEN;
  142. memcpy(thread_readdata.base + truepacketlen, thread_packetdata.base, theNexPacket.datalen + 1);
  143. truepacketlen += theNexPacket.datalen + 1;
  144. }
  145. parsetype = PARSE_NOTHING;//重头再来
  146. continue;
  147. }
  148. if (0 == theNexPacket.datalen) { //长度为0的md5为:d41d8cd98f00b204e9800998ecf8427e,改为全0
  149. memset(md5str, 0, sizeof(md5str));
  150. } else {
  151. MD5_CTX md5;
  152. MD5_Init(&md5);
  153. MD5_Update(&md5, thread_packetdata.base, theNexPacket.datalen); //包数据的校验值
  154. MD5_Final(md5str, &md5);
  155. }
  156. if (memcmp(theNexPacket.check, md5str, MD5_DIGEST_LENGTH) != 0) {
  157. fprintf(stdout, "读取%d数据, 校验码不合法\n", NET_PACKAGE_HEADLEN + theNexPacket.datalen + 2);
  158. if (truepacketlen - headpos - 1 - NET_PACKAGE_HEADLEN >= theNexPacket.datalen + 1) {//thread_readdata数据足够
  159. memmove(thread_readdata.base, thread_readdata.base + headpos + 1, truepacketlen - headpos - 1); //2.4
  160. truepacketlen -= headpos + 1;
  161. } else {//thread_readdata数据不足
  162. if (thread_readdata.len < NET_PACKAGE_HEADLEN + theNexPacket.datalen + 1) {//包含最后的tail
  163. thread_readdata.base = (char*)realloc(thread_readdata.base, NET_PACKAGE_HEADLEN + theNexPacket.datalen + 1);
  164. thread_readdata.len = NET_PACKAGE_HEADLEN + theNexPacket.datalen + 1;
  165. }
  166. memmove(thread_readdata.base, thread_readdata.base + headpos + 1, NET_PACKAGE_HEADLEN); //2.4
  167. truepacketlen = NET_PACKAGE_HEADLEN;
  168. memcpy(thread_readdata.base + truepacketlen, thread_packetdata.base, theNexPacket.datalen + 1);
  169. truepacketlen += theNexPacket.datalen + 1;
  170. }
  171. parsetype = PARSE_NOTHING;//重头再来
  172. continue;
  173. }
  174. if (truepacketlen - headpos - 1 - NET_PACKAGE_HEADLEN >= theNexPacket.datalen + 1) {//thread_readdata数据足够
  175. memmove(thread_readdata.base, thread_readdata.base + headpos + NET_PACKAGE_HEADLEN + theNexPacket.datalen + 2,
  176. truepacketlen - (headpos + NET_PACKAGE_HEADLEN + theNexPacket.datalen + 2)); //2.4
  177. truepacketlen -= headpos + NET_PACKAGE_HEADLEN + theNexPacket.datalen + 2;
  178. } else {
  179. truepacketlen = 0;//从新开始读取数据
  180. }
  181. //回调帧数据给用户
  182. if (this->packet_cb_) {
  183. this->packet_cb_(theNexPacket, (const unsigned char*)thread_packetdata.base, this->packetcb_userdata_);
  184. }
  185. parsetype = PARSE_NOTHING;//重头再来
  186. }
  187. }
  188. void SetPacketCB(GetFullPacket pfun, void* userdata) {
  189. packet_cb_ = pfun;
  190. packetcb_userdata_ = userdata;
  191. }
  192. private:
  193. GetFullPacket packet_cb_;//回调函数
  194. void* packetcb_userdata_;//回调函数所带的自定义数据
  195. enum {
  196. PARSE_HEAD,
  197. PARSE_NOTHING,
  198. };
  199. int parsetype;
  200. int getdatalen;
  201. uv_buf_t thread_readdata;//负责从circulebuffer_读取数据
  202. uv_buf_t thread_packetdata;//负责从circulebuffer_读取packet 中data部分
  203. int truepacketlen;//readdata有效数据长度
  204. int headpos;//找到头位置
  205. char* headpt;//找到头位置
  206. unsigned char HEAD;//包头
  207. unsigned char TAIL;//包尾
  208. NetPacket theNexPacket;
  209. unsigned char md5str[MD5_DIGEST_LENGTH];
  210. private:// no copy
  211. PacketSync(const PacketSync&);
  212. PacketSync& operator = (const PacketSync&);
  213. };
  214. /***********************************************辅助函数***************************************************/
  215. /*****************************
  216. * @brief 把数据组合成NetPacket格式的二进制流,可直接发送。
  217. * @param packet --NetPacket包,里面的version,header,tail,type,datalen,reserve必须提前赋值,该函数会计算check的值。然后组合成二进制流返回
  218. data --要发送的实际数据
  219. * @return std::string --返回的二进制流。地址:&string[0],长度:string.length()
  220. ******************************/
  221. inline std::string PacketData(NetPacket& packet, const unsigned char* data)
  222. {
  223. if (packet.datalen == 0 || data == NULL) {//长度为0的md5为:d41d8cd98f00b204e9800998ecf8427e,改为全0
  224. memset(packet.check, 0, sizeof(packet.check));
  225. } else {
  226. MD5_CTX md5;
  227. MD5_Init(&md5);
  228. MD5_Update(&md5, data, packet.datalen);
  229. MD5_Final(packet.check, &md5);
  230. }
  231. unsigned char packchar[NET_PACKAGE_HEADLEN];
  232. NetPacketToChar(packet, packchar);
  233. std::string retstr;
  234. retstr.append(1, packet.header);
  235. retstr.append((const char*)packchar, NET_PACKAGE_HEADLEN);
  236. retstr.append((const char*)data, packet.datalen);
  237. retstr.append(1, packet.tail);
  238. return std::move(retstr);
  239. }
  240. //客户端或服务器关闭的回调函数
  241. //服务器:当clientid为-1时,表现服务器的关闭事件
  242. //客户端:clientid无效,永远为-1
  243. typedef void (*TcpCloseCB)(int clientid, void* userdata);
  244. //TCPServer接收到新客户端回调给用户
  245. typedef void (*NewConnectCB)(int clientid, void* userdata);
  246. //TCPServer接收到客户端数据回调给用户
  247. typedef void (*ServerRecvCB)(int clientid, const NetPacket& packethead, const unsigned char* buf, void* userdata);
  248. //TCPClient接收到服务器数据回调给用户
  249. typedef void (*ClientRecvCB)(const NetPacket& packethead, const unsigned char* buf, void* userdata);
  250. //网络事件类型
  251. typedef enum {
  252. NET_EVENT_TYPE_RECONNECT = 0, //与服务器自动重连成功事件
  253. NET_EVENT_TYPE_DISCONNECT //与服务器断开事件
  254. } NET_EVENT_TYPE;
  255. //TCPClient断线重连函数
  256. typedef void (*ReconnectCB)(NET_EVENT_TYPE eventtype, void* userdata);
  257. #endif//PACKET_SYNC_H