Websocket消息帧粘包,拆包及处理方法

问题:

接收客户端消息处理时,遇到这样情况;接收第一帧数据时正常的,后面再次接受解析数据帧时,发现解析的消息是异常、缺失的,导致服务端不能正确接收消息。

查了相关资料,发现tcp再传输数据时,发送消息并非一包一包发送,存在粘包、拆包的情况。

粘包、拆包表现形式

现在假设客户端向服务端连续发送了两个数据包,用packet1和packet2来表示,那么服务端收到的数据可以分为三种,现列举如下:

第一种情况(正常情况)

接收端正常收到两个数据包,即没有发生拆包和粘包的现象,此种情况不在本文的讨论范围内。

第二种情况(粘包:两帧数据放在一个tcp消息包中)

     接收端只收到一个数据包,由于TCP是不会出现丢包的,所以这一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理。

第三种情况(拆包:一帧数据被拆分在两个tcp消息包中)

      这种情况有两种表现形式,如下图。接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。这两种情况如果不加特殊处理,对于接收端同样是不好处理的。

粘包、拆包发生原因

发生TCP粘包或拆包有很多原因,现列出常见的几点,可能不全面,欢迎补充,

1、要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。

2、待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。

3、要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。

4、接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

等等。

粘包、拆包解决办法

通过以上分析,我们清楚了粘包或拆包发生的原因,那么如何解决这个问题呢?解决问题的关键在于如何给每个数据包添加边界信息,常用的方法有如下几个:

1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。

3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

等等。

样例程序

我将在程序中使用两种方法来解决粘包和拆包问题,固定数据包长度和添加长度首部,这两种方法各有优劣。

固定数据包长度传输效率一般,尤其是在要发送的数据长度长短差别很大的时候效率会比较低,但是编程实现比较简单;

添加长度首部虽然可以获得较高的传输效率,冗余信息少且固定,但是编程实现较为复杂。

websocket是包含消息头部的,所以样例程序采用首部验证方法

固定数据包长度

这种处理方式的思路很简单,发送端在发送实际数据前先把数据封装为固定长度,然后在发送出去,接收端接收到数据后按照这个固定长度进行拆分即可。处理省略。。。

添加长度首部

这种方式的处理较上面提到的方式稍微复杂一点。在发送端需要给待发送的数据添加固定的首部,然后再发送出去,然后在接收端需要根据这个首部的长度信息进行数据包的组合或拆分,发送端程序如下:

  1. #include "websocket_common.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h> // 使用 malloc, calloc等动态分配内存方法
  5. #include <time.h> // 获取系统时间
  6. #include <errno.h>
  7. #include <fcntl.h> // 非阻塞
  8. #include <sys/un.h>
  9. #include <arpa/inet.h> // inet_addr()
  10. #include <unistd.h> // close()
  11. #include <sys/types.h> // 文件IO操作
  12. #include <sys/socket.h> //
  13. #include <netinet/in.h>
  14. #include <netinet/ip.h>
  15. #include <netinet/ip_icmp.h>
  16. #include <netdb.h> // gethostbyname, gethostbyname2, gethostbyname_r, gethostbyname_r2
  17. #include <sys/un.h>
  18. #include <sys/time.h>
  19. #include <arpa/inet.h>
  20. #include <net/if.h>
  21. #include <sys/ioctl.h> // SIOCSIFADDR
  22. //==============================================================================================
  23. //======================================== 设置和工具部分 =======================================
  24. //==============================================================================================
  25. // 连接服务器
  26. #define WEBSOCKET_LOGIN_CONNECT_TIMEOUT 1000 // 登录连接超时设置 1000ms
  27. #define WEBSOCKET_LOGIN_RESPOND_TIMEOUT (1000 + WEBSOCKET_LOGIN_CONNECT_TIMEOUT) // 登录等待回应超时设置 1000ms
  28. // 发收
  29. // 生成握手key的长度
  30. #define WEBSOCKET_SHAKE_KEY_LEN 16
  31. //==================== delay ms ====================
  32. void webSocket_delayms(unsigned int ms)
  33. {
  34. struct timeval tim;
  35. tim.tv_sec = ms/1000;
  36. tim.tv_usec = (ms%1000)*1000;
  37. select(0, NULL, NULL, NULL, &tim);
  38. }
  39. //-------------------- IP控制 --------------------
  40. int netCheck_setIP(char *devName, char *ip)
  41. {
  42. struct ifreq temp;
  43. struct sockaddr_in *addr;
  44. int fd, ret;
  45. //
  46. strcpy(temp.ifr_name, devName);
  47. if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  48. return -1;
  49. //
  50. addr = (struct sockaddr_in *)&(temp.ifr_addr);
  51. addr->sin_family = AF_INET;
  52. addr->sin_addr.s_addr = inet_addr(ip);
  53. ret = ioctl(fd, SIOCSIFADDR, &temp);
  54. //
  55. close(fd);
  56. if(ret < 0)
  57. return -1;
  58. return 0;
  59. }
  60. void netCheck_getIP(char *devName, char *ip)
  61. {
  62. struct ifreq temp;
  63. struct sockaddr_in *addr;
  64. int fd, ret;
  65. //
  66. strcpy(temp.ifr_name, devName);
  67. if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  68. return;
  69. ret = ioctl(fd, SIOCGIFADDR, &temp);
  70. close(fd);
  71. if(ret < 0)
  72. return;
  73. //
  74. addr = (struct sockaddr_in *)&(temp.ifr_addr);
  75. strcpy(ip, inet_ntoa(addr->sin_addr));
  76. //
  77. // return ip;
  78. }
  79. //==================== 域名转IP ====================
  80. typedef struct{
  81. pthread_t thread_id;
  82. char ip[256];
  83. bool result;
  84. bool actionEnd;
  85. }GetHostName_Struct;
  86. //
  87. void *websocket_getHost_fun(void *arge)
  88. {
  89. int ret;
  90. //int i;
  91. char buf[1024];
  92. struct hostent host_body, *host = NULL;
  93. struct in_addr **addr_list;
  94. GetHostName_Struct *gs = (GetHostName_Struct *)arge;
  95. /* 此类方法不可重入! 即使关闭线程
  96. if((host = gethostbyname(gs->ip)) == NULL)
  97. //if((host = gethostbyname2(gs->ip, AF_INET)) == NULL)
  98. {
  99. gs->actionEnd = true;
  100. return NULL;
  101. }*/
  102. if(gethostbyname_r(gs->ip, &host_body, buf, sizeof(buf), &host, &ret))
  103. {
  104. gs->actionEnd = true;
  105. return NULL;
  106. }
  107. if(host == NULL)
  108. {
  109. gs->actionEnd = true;
  110. return NULL;
  111. }
  112. addr_list = (struct in_addr **)host->h_addr_list;
  113. //printf("ip name : %s\r\nip list : ", host->h_name);
  114. //for(i = 0; addr_list[i] != NULL; i++) printf("%s, ", inet_ntoa(*addr_list[i])); printf("\r\n");
  115. if(addr_list[0] == NULL)
  116. {
  117. gs->actionEnd = true;
  118. return NULL;
  119. }
  120. memset(gs->ip, 0, sizeof(gs->ip));
  121. strcpy(gs->ip, (char *)(inet_ntoa(*addr_list[0])));
  122. gs->result = true;
  123. gs->actionEnd = true;
  124. return NULL;
  125. }
  126. //
  127. int websocket_getIpByHostName(char *hostName, char *backIp)
  128. {
  129. int i, timeOut = 1;
  130. GetHostName_Struct gs;
  131. if(hostName == NULL)
  132. return -1;
  133. else if(strlen(hostName) < 1)
  134. return -1;
  135. //----- 开线程从域名获取IP -----
  136. memset(&gs, 0, sizeof(GetHostName_Struct));
  137. strcpy(gs.ip, hostName);
  138. gs.result = false;
  139. gs.actionEnd = false;
  140. if (pthread_create(&gs.thread_id, NULL, (void *)websocket_getHost_fun, &gs) < 0)
  141. return -1;
  142. i = 0;
  143. while(!gs.actionEnd)
  144. {
  145. if(++i > 10)
  146. {
  147. i = 0;
  148. if(++timeOut > 1000)
  149. break;
  150. }
  151. webSocket_delayms(1000);// 1ms延时
  152. }
  153. // pthread_cancel(gs.thread_id);
  154. pthread_join(gs.thread_id, NULL);
  155. if(!gs.result)
  156. return -timeOut;
  157. //----- 开线程从域名获取IP -----
  158. memset(backIp, 0, strlen(backIp));
  159. strcpy(backIp, gs.ip);
  160. return timeOut;
  161. }
  162. //==================== 加密方法BASE64 ====================
  163. //base64编/解码用的基础字符集
  164. const char websocket_base64char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  165. /*******************************************************************************
  166. * 名称: websocket_base64_encode
  167. * 功能: ascii编码为base64格式
  168. * 形参: bindata : ascii字符串输入
  169. * base64 : base64字符串输出
  170. * binlength : bindata的长度
  171. * 返回: base64字符串长度
  172. * 说明: 无
  173. ******************************************************************************/
  174. int websocket_base64_encode( const unsigned char *bindata, char *base64, int binlength)
  175. {
  176. int i, j;
  177. unsigned char current;
  178. for ( i = 0, j = 0 ; i < binlength ; i += 3 )
  179. {
  180. current = (bindata[i] >> 2) ;
  181. current &= (unsigned char)0x3F;
  182. base64[j++] = websocket_base64char[(int)current];
  183. current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ;
  184. if ( i + 1 >= binlength )
  185. {
  186. base64[j++] = websocket_base64char[(int)current];
  187. base64[j++] = '=';
  188. base64[j++] = '=';
  189. break;
  190. }
  191. current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F );
  192. base64[j++] = websocket_base64char[(int)current];
  193. current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ;
  194. if ( i + 2 >= binlength )
  195. {
  196. base64[j++] = websocket_base64char[(int)current];
  197. base64[j++] = '=';
  198. break;
  199. }
  200. current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 );
  201. base64[j++] = websocket_base64char[(int)current];
  202. current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ;
  203. base64[j++] = websocket_base64char[(int)current];
  204. }
  205. base64[j] = '\0';
  206. return j;
  207. }
  208. /*******************************************************************************
  209. * 名称: websocket_base64_decode
  210. * 功能: base64格式解码为ascii
  211. * 形参: base64 : base64字符串输入
  212. * bindata : ascii字符串输出
  213. * 返回: 解码出来的ascii字符串长度
  214. * 说明: 无
  215. ******************************************************************************/
  216. int websocket_base64_decode( const char *base64, unsigned char *bindata)
  217. {
  218. int i, j;
  219. unsigned char k;
  220. unsigned char temp[4];
  221. for ( i = 0, j = 0; base64[i] != '\0' ; i += 4 )
  222. {
  223. memset( temp, 0xFF, sizeof(temp) );
  224. for ( k = 0 ; k < 64 ; k ++ )
  225. {
  226. if ( websocket_base64char[k] == base64[i] )
  227. temp[0]= k;
  228. }
  229. for ( k = 0 ; k < 64 ; k ++ )
  230. {
  231. if ( websocket_base64char[k] == base64[i+1] )
  232. temp[1]= k;
  233. }
  234. for ( k = 0 ; k < 64 ; k ++ )
  235. {
  236. if ( websocket_base64char[k] == base64[i+2] )
  237. temp[2]= k;
  238. }
  239. for ( k = 0 ; k < 64 ; k ++ )
  240. {
  241. if ( websocket_base64char[k] == base64[i+3] )
  242. temp[3]= k;
  243. }
  244. bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] << 2))&0xFC)) | \
  245. ((unsigned char)((unsigned char)(temp[1]>>4)&0x03));
  246. if ( base64[i+2] == '=' )
  247. break;
  248. bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) | \
  249. ((unsigned char)((unsigned char)(temp[2]>>2)&0x0F));
  250. if ( base64[i+3] == '=' )
  251. break;
  252. bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) | \
  253. ((unsigned char)(temp[3]&0x3F));
  254. }
  255. return j;
  256. }
  257. //==================== 加密方法 sha1哈希 ====================
  258. typedef struct SHA1Context{
  259. unsigned Message_Digest[5];
  260. unsigned Length_Low;
  261. unsigned Length_High;
  262. unsigned char Message_Block[64];
  263. int Message_Block_Index;
  264. int Computed;
  265. int Corrupted;
  266. } SHA1Context;
  267. #define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
  268. void SHA1ProcessMessageBlock(SHA1Context *context)
  269. {
  270. const unsigned K[] = {0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
  271. int t;
  272. unsigned temp;
  273. unsigned W[80];
  274. unsigned A, B, C, D, E;
  275. for(t = 0; t < 16; t++)
  276. {
  277. W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
  278. W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
  279. W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
  280. W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
  281. }
  282. for(t = 16; t < 80; t++)
  283. W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
  284. A = context->Message_Digest[0];
  285. B = context->Message_Digest[1];
  286. C = context->Message_Digest[2];
  287. D = context->Message_Digest[3];
  288. E = context->Message_Digest[4];
  289. for(t = 0; t < 20; t++)
  290. {
  291. temp = SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
  292. temp &= 0xFFFFFFFF;
  293. E = D;
  294. D = C;
  295. C = SHA1CircularShift(30,B);
  296. B = A;
  297. A = temp;
  298. }
  299. for(t = 20; t < 40; t++)
  300. {
  301. temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
  302. temp &= 0xFFFFFFFF;
  303. E = D;
  304. D = C;
  305. C = SHA1CircularShift(30,B);
  306. B = A;
  307. A = temp;
  308. }
  309. for(t = 40; t < 60; t++)
  310. {
  311. temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
  312. temp &= 0xFFFFFFFF;
  313. E = D;
  314. D = C;
  315. C = SHA1CircularShift(30,B);
  316. B = A;
  317. A = temp;
  318. }
  319. for(t = 60; t < 80; t++)
  320. {
  321. temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
  322. temp &= 0xFFFFFFFF;
  323. E = D;
  324. D = C;
  325. C = SHA1CircularShift(30,B);
  326. B = A;
  327. A = temp;
  328. }
  329. context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;
  330. context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;
  331. context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;
  332. context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;
  333. context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;
  334. context->Message_Block_Index = 0;
  335. }
  336. void SHA1Reset(SHA1Context *context)
  337. {
  338. context->Length_Low = 0;
  339. context->Length_High = 0;
  340. context->Message_Block_Index = 0;
  341. context->Message_Digest[0] = 0x67452301;
  342. context->Message_Digest[1] = 0xEFCDAB89;
  343. context->Message_Digest[2] = 0x98BADCFE;
  344. context->Message_Digest[3] = 0x10325476;
  345. context->Message_Digest[4] = 0xC3D2E1F0;
  346. context->Computed = 0;
  347. context->Corrupted = 0;
  348. }
  349. void SHA1PadMessage(SHA1Context *context)
  350. {
  351. if (context->Message_Block_Index > 55)
  352. {
  353. context->Message_Block[context->Message_Block_Index++] = 0x80;
  354. while(context->Message_Block_Index < 64) context->Message_Block[context->Message_Block_Index++] = 0;
  355. SHA1ProcessMessageBlock(context);
  356. while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
  357. }
  358. else
  359. {
  360. context->Message_Block[context->Message_Block_Index++] = 0x80;
  361. while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
  362. }
  363. context->Message_Block[56] = (context->Length_High >> 24 ) & 0xFF;
  364. context->Message_Block[57] = (context->Length_High >> 16 ) & 0xFF;
  365. context->Message_Block[58] = (context->Length_High >> 8 ) & 0xFF;
  366. context->Message_Block[59] = (context->Length_High) & 0xFF;
  367. context->Message_Block[60] = (context->Length_Low >> 24 ) & 0xFF;
  368. context->Message_Block[61] = (context->Length_Low >> 16 ) & 0xFF;
  369. context->Message_Block[62] = (context->Length_Low >> 8 ) & 0xFF;
  370. context->Message_Block[63] = (context->Length_Low) & 0xFF;
  371. SHA1ProcessMessageBlock(context);
  372. }
  373. int SHA1Result(SHA1Context *context)
  374. {
  375. if (context->Corrupted)
  376. {
  377. return 0;
  378. }
  379. if (!context->Computed)
  380. {
  381. SHA1PadMessage(context);
  382. context->Computed = 1;
  383. }
  384. return 1;
  385. }
  386. void SHA1Input(SHA1Context *context,const char *message_array,unsigned length){
  387. if (!length)
  388. return;
  389. if (context->Computed || context->Corrupted)
  390. {
  391. context->Corrupted = 1;
  392. return;
  393. }
  394. while(length-- && !context->Corrupted)
  395. {
  396. context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);
  397. context->Length_Low += 8;
  398. context->Length_Low &= 0xFFFFFFFF;
  399. if (context->Length_Low == 0)
  400. {
  401. context->Length_High++;
  402. context->Length_High &= 0xFFFFFFFF;
  403. if (context->Length_High == 0) context->Corrupted = 1;
  404. }
  405. if (context->Message_Block_Index == 64)
  406. {
  407. SHA1ProcessMessageBlock(context);
  408. }
  409. message_array++;
  410. }
  411. }
  412. /*
  413. int sha1_hash(const char *source, char *lrvar){// Main
  414. SHA1Context sha;
  415. char buf[128];
  416. SHA1Reset(&sha);
  417. SHA1Input(&sha, source, strlen(source));
  418. if (!SHA1Result(&sha)){
  419. printf("SHA1 ERROR: Could not compute message digest");
  420. return -1;
  421. } else {
  422. memset(buf,0,sizeof(buf));
  423. sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
  424. sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
  425. //lr_save_string(buf, lrvar);
  426. return strlen(buf);
  427. }
  428. }
  429. */
  430. char * sha1_hash(const char *source){ // Main
  431. SHA1Context sha;
  432. char *buf;//[128];
  433. SHA1Reset(&sha);
  434. SHA1Input(&sha, source, strlen(source));
  435. if (!SHA1Result(&sha))
  436. {
  437. printf("SHA1 ERROR: Could not compute message digest");
  438. return NULL;
  439. }
  440. else
  441. {
  442. buf = (char *)malloc(128);
  443. memset(buf, 0, 128);
  444. sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
  445. sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
  446. //lr_save_string(buf, lrvar);
  447. //return strlen(buf);
  448. return buf;
  449. }
  450. }
  451. int tolower(int c)
  452. {
  453. if (c >= 'A' && c <= 'Z')
  454. {
  455. return c + 'a' - 'A';
  456. }
  457. else
  458. {
  459. return c;
  460. }
  461. }
  462. int htoi(const char s[], int start, int len)
  463. {
  464. int i, j;
  465. int n = 0;
  466. if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) //判断是否有前导0x或者0X
  467. {
  468. i = 2;
  469. }
  470. else
  471. {
  472. i = 0;
  473. }
  474. i+=start;
  475. j=0;
  476. for (; (s[i] >= '0' && s[i] <= '9')
  477. || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >='A' && s[i] <= 'F');++i)
  478. {
  479. if(j>=len)
  480. {
  481. break;
  482. }
  483. if (tolower(s[i]) > '9')
  484. {
  485. n = 16 * n + (10 + tolower(s[i]) - 'a');
  486. }
  487. else
  488. {
  489. n = 16 * n + (tolower(s[i]) - '0');
  490. }
  491. j++;
  492. }
  493. return n;
  494. }
  495. //==============================================================================================
  496. //======================================== websocket部分 =======================================
  497. //==============================================================================================
  498. // websocket根据data[0]判别数据包类型
  499. // typedef enum{
  500. // WDT_MINDATA = -20, // 0x0:标识一个中间数据包
  501. // WDT_TXTDATA = -19, // 0x1:标识一个text类型数据包
  502. // WDT_BINDATA = -18, // 0x2:标识一个binary类型数据包
  503. // WDT_DISCONN = -17, // 0x8:标识一个断开连接类型数据包
  504. // WDT_PING = -16, // 0x8:标识一个断开连接类型数据包
  505. // WDT_PONG = -15, // 0xA:表示一个pong类型数据包
  506. // WDT_ERR = -1,
  507. // WDT_NULL = 0
  508. // }WebsocketData_Type;
  509. /*******************************************************************************
  510. * 名称: webSocket_getRandomString
  511. * 功能: 生成随机字符串
  512. * 形参: *buf:随机字符串存储到
  513. * len : 生成随机字符串长度
  514. * 返回: 无
  515. * 说明: 无
  516. ******************************************************************************/
  517. void webSocket_getRandomString(unsigned char *buf, unsigned int len)
  518. {
  519. unsigned int i;
  520. unsigned char temp;
  521. srand((int)time(0));
  522. for(i = 0; i < len; i++)
  523. {
  524. temp = (unsigned char)(rand()%256);
  525. if(temp == 0) // 随机数不要0, 0 会干扰对字符串长度的判断
  526. temp = 128;
  527. buf[i] = temp;
  528. }
  529. }
  530. /*******************************************************************************
  531. * 名称: webSocket_buildShakeKey
  532. * 功能: client端使用随机数构建握手用的key
  533. * 形参: *key:随机生成的握手key
  534. * 返回: key的长度
  535. * 说明: 无
  536. ******************************************************************************/
  537. int webSocket_buildShakeKey(unsigned char *key)
  538. {
  539. unsigned char tempKey[WEBSOCKET_SHAKE_KEY_LEN] = {0};
  540. webSocket_getRandomString(tempKey, WEBSOCKET_SHAKE_KEY_LEN);
  541. return websocket_base64_encode((const unsigned char *)tempKey, (char *)key, WEBSOCKET_SHAKE_KEY_LEN);
  542. }
  543. /*******************************************************************************
  544. * 名称: webSocket_buildRespondShakeKey
  545. * 功能: server端在接收client端的key后,构建回应用的key
  546. * 形参: *acceptKey:来自客户端的key字符串
  547. * acceptKeyLen : 长度
  548. * *respondKey : 在 acceptKey 之后加上 GUID, 再sha1哈希, 再转成base64得到 respondKey
  549. * 返回: respondKey的长度(肯定比acceptKey要长)
  550. * 说明: 无
  551. ******************************************************************************/
  552. int webSocket_buildRespondShakeKey(unsigned char *acceptKey, unsigned int acceptKeyLen, unsigned char *respondKey)
  553. {
  554. char *clientKey;
  555. char *sha1DataTemp;
  556. char *sha1Data;
  557. int i, n;
  558. const char GUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  559. unsigned int GUIDLEN;
  560. if(acceptKey == NULL)
  561. return 0;
  562. GUIDLEN = sizeof(GUID);
  563. clientKey = (char *)calloc(acceptKeyLen + GUIDLEN + 10, sizeof(char));
  564. memset(clientKey, 0, (acceptKeyLen + GUIDLEN + 10));
  565. //
  566. memcpy(clientKey, acceptKey, acceptKeyLen);
  567. memcpy(&clientKey[acceptKeyLen], GUID, GUIDLEN);
  568. clientKey[acceptKeyLen + GUIDLEN] = '\0';
  569. //
  570. sha1DataTemp = sha1_hash(clientKey);
  571. n = strlen((const char *)sha1DataTemp);
  572. sha1Data = (char *)calloc(n / 2 + 1, sizeof(char));
  573. memset(sha1Data, 0, n / 2 + 1);
  574. //
  575. for(i = 0; i < n; i += 2)
  576. sha1Data[ i / 2 ] = htoi(sha1DataTemp, i, 2);
  577. n = websocket_base64_encode((const unsigned char *)sha1Data, (char *)respondKey, (n / 2));
  578. //
  579. free(sha1DataTemp);
  580. free(sha1Data);
  581. free(clientKey);
  582. return n;
  583. }
  584. /*******************************************************************************
  585. * 名称: webSocket_matchShakeKey
  586. * 功能: client端收到来自服务器回应的key后进行匹配,以验证握手成功
  587. * 形参: *myKey:client端请求握手时发给服务器的key
  588. * myKeyLen : 长度
  589. * *acceptKey : 服务器回应的key
  590. * acceptKeyLen : 长度
  591. * 返回: 0 成功 -1 失败
  592. * 说明: 无
  593. ******************************************************************************/
  594. int webSocket_matchShakeKey(unsigned char *myKey, unsigned int myKeyLen, unsigned char *acceptKey, unsigned int acceptKeyLen)
  595. {
  596. int retLen;
  597. unsigned char tempKey[256] = {0};
  598. //
  599. retLen = webSocket_buildRespondShakeKey(myKey, myKeyLen, tempKey);
  600. //printf("webSocket_matchShakeKey :\r\n%d : %s\r\n%d : %s\r\n", acceptKeyLen, acceptKey, retLen, tempKey);
  601. //
  602. if(retLen != acceptKeyLen)
  603. {
  604. printf("webSocket_matchShakeKey : len err\r\n%s\r\n%s\r\n%s\r\n", myKey, tempKey, acceptKey);
  605. return -1;
  606. }
  607. else if(strcmp((const char *)tempKey, (const char *)acceptKey) != 0)
  608. {
  609. printf("webSocket_matchShakeKey : str err\r\n%s\r\n%s\r\n", tempKey, acceptKey);
  610. return -1;
  611. }
  612. return 0;
  613. }
  614. /*******************************************************************************
  615. * 名称: webSocket_buildHttpHead
  616. * 功能: 构建client端连接服务器时的http协议头, 注意websocket是GET形式的
  617. * 形参: *ip:要连接的服务器ip字符串
  618. * port : 服务器端口
  619. * *interfacePath : 要连接的端口地址
  620. * *shakeKey : 握手key, 可以由任意的16位字符串打包成base64后得到
  621. * *package : 存储最后打包好的内容
  622. * 返回: 无
  623. * 说明: 无
  624. ******************************************************************************/
  625. void webSocket_buildHttpHead(char *ip, int port, char *interfacePath, unsigned char *shakeKey, char *package)
  626. {
  627. const char httpDemo[] = "GET %s HTTP/1.1\r\n"
  628. "Connection: Upgrade\r\n"
  629. "Host: %s:%d\r\n"
  630. "Sec-WebSocket-Key: %s\r\n"
  631. "Sec-WebSocket-Version: 13\r\n"
  632. "Upgrade: websocket\r\n\r\n";
  633. sprintf(package, httpDemo, interfacePath, ip, port, shakeKey);
  634. }
  635. /*******************************************************************************
  636. * 名称: webSocket_buildHttpRespond
  637. * 功能: 构建server端回复client连接请求的http协议
  638. * 形参: *acceptKey:来自client的握手key
  639. * acceptKeyLen : 长度
  640. * *package : 存储
  641. * 返回: 无
  642. * 说明: 无
  643. ******************************************************************************/
  644. void webSocket_buildHttpRespond(unsigned char *acceptKey, unsigned int acceptKeyLen, char *package)
  645. {
  646. const char httpDemo[] = "HTTP/1.1 101 Switching Protocols\r\n"
  647. "Upgrade: websocket\r\n"
  648. "Server: Microsoft-HTTPAPI/2.0\r\n"
  649. "Connection: Upgrade\r\n"
  650. "Sec-WebSocket-Accept: %s\r\n"
  651. "%s\r\n\r\n"; // 时间打包待续 // 格式如 "Date: Tue, 20 Jun 2017 08:50:41 CST\r\n"
  652. time_t now;
  653. struct tm *tm_now;
  654. char timeStr[256] = {0};
  655. unsigned char respondShakeKey[256] = {0};
  656. // 构建回应的握手key
  657. webSocket_buildRespondShakeKey(acceptKey, acceptKeyLen, respondShakeKey);
  658. // 构建回应时间字符串
  659. time(&now);
  660. tm_now = localtime(&now);
  661. strftime(timeStr, sizeof(timeStr), "Date: %a, %d %b %Y %T %Z", tm_now);
  662. // 组成回复信息
  663. sprintf(package, httpDemo, respondShakeKey, timeStr);
  664. }
  665. /*******************************************************************************
  666. * 名称: webSocket_enPackage
  667. * 功能: websocket数据收发阶段的数据打包, 通常client发server的数据都要isMask(掩码)处理, 反之server到client却不用
  668. * 形参: *data:准备发出的数据
  669. * dataLen : 长度
  670. * *package : 打包后存储地址
  671. * packageMaxLen : 存储地址可用长度
  672. * isMask : 是否使用掩码 1要 0 不要
  673. * type : 数据类型, 由打包后第一个字节决定, 这里默认是数据传输, 即0x81
  674. * 返回: 打包后的长度(会比原数据长2~16个字节不等) <=0 打包失败
  675. * 说明: 无
  676. ******************************************************************************/
  677. int webSocket_enPackage(unsigned char *data, unsigned int dataLen, unsigned char *package, unsigned int packageMaxLen, bool isMask, WebsocketData_Type type)
  678. {
  679. unsigned char maskKey[4] = {0}; // 掩码
  680. unsigned char temp1, temp2;
  681. int count;
  682. unsigned int i, len = 0;
  683. if(packageMaxLen < 2)
  684. return -1;
  685. if(type == WDT_MINDATA)
  686. *package++ = 0x00;
  687. else if(type == WDT_TXTDATA)
  688. *package++ = 0x81;
  689. else if(type == WDT_BINDATA)
  690. *package++ = 0x82;
  691. else if(type == WDT_DISCONN)
  692. *package++ = 0x88;
  693. else if(type == WDT_PING)
  694. *package++ = 0x89;
  695. else if(type == WDT_PONG)
  696. *package++ = 0x8A;
  697. else if(type == 100)
  698. *package++ = 0x02;//add by cheyang//return -1;
  699. else if(type == 99)
  700. *package++ = 0x80;//add by cheyang//return -1;
  701. //
  702. if(isMask)
  703. *package = 0x80;
  704. len += 1;
  705. //
  706. if(dataLen < 126)
  707. {
  708. *package++ |= (dataLen&0x7F);
  709. len += 1;
  710. }
  711. else if(dataLen < 65536)
  712. {
  713. if(packageMaxLen < 4)
  714. return -1;
  715. *package++ |= 0x7E;
  716. *package++ = (char)((dataLen >> 8) & 0xFF);
  717. *package++ = (unsigned char)((dataLen >> 0) & 0xFF);
  718. len += 3;
  719. }
  720. else if(dataLen < 0xFFFFFFFF)
  721. {
  722. if(packageMaxLen < 10)
  723. return -1;
  724. *package++ |= 0x7F;
  725. *package++ = 0; //(char)((dataLen >> 56) & 0xFF); // 数据长度变量是 unsigned int dataLen, 暂时没有那么多数据
  726. *package++ = 0; //(char)((dataLen >> 48) & 0xFF);
  727. *package++ = 0; //(char)((dataLen >> 40) & 0xFF);
  728. *package++ = 0; //(char)((dataLen >> 32) & 0xFF);
  729. *package++ = (char)((dataLen >> 24) & 0xFF); // 到这里就够传4GB数据了
  730. *package++ = (char)((dataLen >> 16) & 0xFF);
  731. *package++ = (char)((dataLen >> 8) & 0xFF);
  732. *package++ = (char)((dataLen >> 0) & 0xFF);
  733. len += 9;
  734. }
  735. //
  736. if(isMask) // 数据使用掩码时, 使用异或解码, maskKey[4]依次和数据异或运算, 逻辑如下
  737. {
  738. if(packageMaxLen < len + dataLen + 4)
  739. return -1;
  740. webSocket_getRandomString(maskKey, sizeof(maskKey)); // 随机生成掩码
  741. *package++ = maskKey[0];
  742. *package++ = maskKey[1];
  743. *package++ = maskKey[2];
  744. *package++ = maskKey[3];
  745. len += 4;
  746. if(type == WDT_TXTDATA){
  747. printf("the key is %d,%d,%d,%d.\n",maskKey[0],maskKey[1],maskKey[2],maskKey[3]);
  748. }
  749. for(i = 0, count = 0; i < dataLen; i++)
  750. {
  751. temp1 = maskKey[count];
  752. temp2 = data[i];
  753. if(type == WDT_TXTDATA){
  754. printf("the file name is %d,key:%d,\n",temp2,maskKey[count]);
  755. }
  756. *package++ = (char)(((~temp1)&temp2) | (temp1&(~temp2))); // 异或运算后得到数据
  757. if(type == WDT_TXTDATA){
  758. printf("after key name is %d,\n",(char)(((~temp1)&temp2) | (temp1&(~temp2))));
  759. }
  760. count += 1;
  761. if(count >= sizeof(maskKey)) // maskKey[4]循环使用
  762. count = 0;
  763. }
  764. len += i;
  765. *package = '\0';
  766. }
  767. else // 数据没使用掩码, 直接复制数据段
  768. {
  769. if(packageMaxLen < len + dataLen)
  770. return -1;
  771. memcpy(package, data, dataLen);
  772. package[dataLen] = '\0';
  773. len += dataLen;
  774. }
  775. //
  776. return len;
  777. }
  778. /*******************************************************************************
  779. * 名称: webSocket_dePackage
  780. * 功能: websocket数据收发阶段的数据解包, 通常client发server的数据都要isMask(掩码)处理, 反之server到client却不用
  781. * 形参: *data:解包的数据
  782. * dataLen : 长度
  783. * *package : 解包后存储地址
  784. * packageMaxLen : 存储地址可用长度
  785. * *packageLen : 解包所得长度
  786. * 返回: 解包识别的数据类型 如 : txt数据, bin数据, ping, pong等
  787. * 说明: 无
  788. ******************************************************************************/
  789. int webSocket_dePackage(unsigned char *data, unsigned int dataLen, unsigned char *package, unsigned int packageMaxLen, unsigned int *packageLen, unsigned int *packageHeadLen)
  790. {
  791. unsigned char maskKey[4] = {0}; // 掩码
  792. unsigned char temp1, temp2;
  793. char Mask = 0, type;
  794. int count, ret;
  795. unsigned int i, len = 0, dataStart = 2;
  796. if(dataLen < 2)
  797. return WDT_ERR;
  798. type = data[0]&0x0F;
  799. if((data[0]&0x80) == 0x80)
  800. {
  801. if(type == 0x01)
  802. ret = WDT_TXTDATA;
  803. else if(type == 0x02)
  804. ret = WDT_BINDATA;
  805. else if(type == 0x08)
  806. ret = WDT_DISCONN;
  807. else if(type == 0x09)
  808. ret = WDT_PING;
  809. else if(type == 0x0A)
  810. ret = WDT_PONG;
  811. else
  812. return WDT_ERR;
  813. }
  814. else if(type == 0x00)
  815. ret = WDT_MINDATA;
  816. else
  817. return WDT_ERR;
  818. //
  819. if((data[1] & 0x80) == 0x80)
  820. {
  821. Mask = 1;
  822. count = 4;
  823. }
  824. else
  825. {
  826. Mask = 0;
  827. count = 0;
  828. }
  829. //
  830. len = data[1] & 0x7F;
  831. //
  832. if(len == 126)
  833. {
  834. if(dataLen < 4)
  835. return WDT_ERR;
  836. len = data[2];
  837. len = (len << 8) + data[3];
  838. if(packageLen) *packageLen = len;//转储包长度
  839. if(packageHeadLen) *packageHeadLen = 4 + count;
  840. //
  841. if(dataLen < len + 4 + count)
  842. return WDT_ERR;
  843. if(Mask)
  844. {
  845. maskKey[0] = data[4];
  846. maskKey[1] = data[5];
  847. maskKey[2] = data[6];
  848. maskKey[3] = data[7];
  849. dataStart = 8;
  850. }
  851. else
  852. dataStart = 4;
  853. }
  854. else if(len == 127)
  855. {
  856. if(dataLen < 10)
  857. return WDT_ERR;
  858. if(data[2] != 0 || data[3] != 0 || data[4] != 0 || data[5] != 0) //使用8个字节存储长度时,前4位必须为0,装不下那么多数据...
  859. return WDT_ERR;
  860. len = data[6];
  861. len = (len << 8) + data[7];
  862. len = (len << 8) + data[8];
  863. len = (len << 8) + data[9];
  864. if(packageLen) *packageLen = len;//转储包长度
  865. if(packageHeadLen) *packageHeadLen = 10 + count;
  866. //
  867. if(dataLen < len + 10 + count)
  868. return WDT_ERR;
  869. if(Mask)
  870. {
  871. maskKey[0] = data[10];
  872. maskKey[1] = data[11];
  873. maskKey[2] = data[12];
  874. maskKey[3] = data[13];
  875. dataStart = 14;
  876. }
  877. else
  878. dataStart = 10;
  879. }
  880. else
  881. {
  882. if(packageLen) *packageLen = len;//转储包长度
  883. if(packageHeadLen) *packageHeadLen = 2 + count;
  884. //
  885. if(dataLen < len + 2 + count)
  886. return WDT_ERR;
  887. if(Mask)
  888. {
  889. maskKey[0] = data[2];
  890. maskKey[1] = data[3];
  891. maskKey[2] = data[4];
  892. maskKey[3] = data[5];
  893. dataStart = 6;
  894. }
  895. else
  896. dataStart = 2;
  897. }
  898. //
  899. if(dataLen < len + dataStart)
  900. return WDT_ERR;
  901. //
  902. if(packageMaxLen < len + 1)
  903. return WDT_ERR;
  904. //
  905. if(Mask) // 解包数据使用掩码时, 使用异或解码, maskKey[4]依次和数据异或运算, 逻辑如下
  906. {
  907. for(i = 0, count = 0; i < len; i++)
  908. {
  909. temp1 = maskKey[count];
  910. temp2 = data[i + dataStart];
  911. *package++ = (char)(((~temp1)&temp2) | (temp1&(~temp2))); // 异或运算后得到数据###与接收端"^"运算符结果一样 by cy###
  912. count += 1;
  913. if(count >= sizeof(maskKey)) // maskKey[4]循环使用
  914. count = 0;
  915. }
  916. *package = '\0';
  917. }
  918. else // 解包数据没使用掩码, 直接复制数据段
  919. {
  920. memcpy(package, &data[dataStart], len);
  921. package[len] = '\0';
  922. }
  923. //
  924. return ret;
  925. }/*******************************************************************************
  926. * 名称: webSocket_clientLinkToServer
  927. * 功能: 向websocket服务器发送http(携带握手key), 以和服务器构建连接, 非阻塞模式
  928. * 形参: *ip:服务器ip
  929. * port : 服务器端口
  930. * *interface_path : 接口地址
  931. * 返回: >0 返回连接句柄 <= 0 连接失败或超时, 所花费的时间 ms
  932. * 说明: 无
  933. ******************************************************************************/
  934. int webSocket_clientLinkToServer(char *ip, int port, char *interface_path)
  935. {
  936. int ret, fd , timeOut;
  937. int i;
  938. unsigned char loginBuf[512] = {0}, recBuf[512] = {0}, shakeKey[128] = {0}, *p;
  939. char tempIp[128] = {0};
  940. //服务器端网络地址结构体
  941. struct sockaddr_in report_addr;
  942. memset(&report_addr,0,sizeof(report_addr)); // 数据初始化--清零
  943. report_addr.sin_family = AF_INET; // 设置为IP通信
  944. //report_addr.sin_addr.s_addr = inet_addr(ip);
  945. if((report_addr.sin_addr.s_addr = inet_addr(ip)) == INADDR_NONE) // 服务器IP地址, 自动域名转换
  946. {
  947. ret = websocket_getIpByHostName(ip, tempIp);
  948. if(ret < 0)
  949. return ret;
  950. else if(strlen(tempIp) < 7)
  951. return -ret;
  952. else
  953. timeOut += ret;
  954. //
  955. if((report_addr.sin_addr.s_addr = inet_addr(tempIp)) == INADDR_NONE)
  956. return -ret;
  957. #ifdef WEBSOCKET_DEBUG
  958. printf("webSocket_clientLinkToServer : Host(%s) to Ip(%s)\r\n", ip, tempIp);
  959. #endif
  960. }
  961. report_addr.sin_port = htons(port); // 服务器端口号
  962. //
  963. //printf("webSocket_clientLinkToServer : ip/%s, port/%d path/%s\r\n", ip, port, interface_path);
  964. //create unix socket
  965. if((fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
  966. {
  967. printf("webSocket_login : cannot create socket\r\n");
  968. return -1;
  969. }
  970. // 测试 ----- 创建握手key 和 匹配返回key
  971. // webSocket_buildShakeKey(shakeKey);
  972. // printf("key1:%s\r\n", shakeKey);
  973. // webSocket_buildRespondShakeKey(shakeKey, strlen(shakeKey), shakeKey);
  974. // printf("key2:%s\r\n", shakeKey);
  975. //非阻塞
  976. ret = fcntl(fd , F_GETFL , 0);
  977. fcntl(fd , F_SETFL , ret | O_NONBLOCK);
  978. //connect
  979. timeOut = 0;
  980. while(connect(fd , (struct sockaddr *)&report_addr,sizeof(struct sockaddr)) == -1)
  981. {
  982. if(++timeOut > WEBSOCKET_LOGIN_CONNECT_TIMEOUT)
  983. {
  984. printf("webSocket_login : cannot connect to %s:%d ! %d\r\n" , ip, port, timeOut);
  985. close(fd);
  986. return -timeOut;
  987. }
  988. webSocket_delayms(1); //1ms
  989. }
  990. //发送http协议头
  991. memset(shakeKey, 0, sizeof(shakeKey));
  992. webSocket_buildShakeKey(shakeKey); // 创建握手key
  993. memset(loginBuf, 0, sizeof(loginBuf)); // 创建协议包
  994. webSocket_buildHttpHead(ip, port, interface_path, shakeKey, (char *)loginBuf);
  995. //发出协议包
  996. ret = send(fd , loginBuf , strlen((const char*)loginBuf) , MSG_NOSIGNAL);
  997. //显示http请求
  998. #ifdef WEBSOCKET_DEBUG
  999. printf("\r\nconnect : %dms\r\nlogin_send:\r\n%s\r\n" , timeOut, loginBuf);
  1000. #endif
  1001. //
  1002. while(1)
  1003. {
  1004. memset(recBuf , 0 , sizeof(recBuf));
  1005. ret = recv(fd , recBuf , sizeof(recBuf) , MSG_NOSIGNAL);
  1006. if(ret > 0)
  1007. {
  1008. if(strncmp((const char *)recBuf, (const char *)"HTTP", strlen((const char *)"HTTP")) == 0) // 返回的是http回应信息
  1009. {
  1010. //显示http返回
  1011. #ifdef WEBSOCKET_DEBUG
  1012. printf("\r\nlogin_recv : %d / %dms\r\n%s\r\n" , ret, timeOut, recBuf);
  1013. #endif
  1014. //
  1015. if((p = (unsigned char *)strstr((const char *)recBuf, (const char *)"Sec-WebSocket-Accept: ")) != NULL) // 定位到握手字符串
  1016. {
  1017. p += strlen((const char *)"Sec-WebSocket-Accept: ");
  1018. sscanf((const char *)p, "%s\r\n", p);
  1019. if(webSocket_matchShakeKey(shakeKey, strlen((const char *)shakeKey), p, strlen((const char *)p)) == 0) // 比对握手信息
  1020. return fd; // 连接成功, 返回连接句柄fd
  1021. else
  1022. ret = send(fd , loginBuf , strlen((const char*)loginBuf) , MSG_NOSIGNAL); // 握手信号不对, 重发协议包
  1023. }
  1024. else
  1025. ret = send(fd , loginBuf , strlen((const char*)loginBuf) , MSG_NOSIGNAL); // 重发协议包
  1026. }
  1027. // #ifdef WEBSOCKET_DEBUG
  1028. // 显示异常返回数据
  1029. else
  1030. {
  1031. if(recBuf[0] >= ' ' && recBuf[0] <= '~')
  1032. printf("\r\nlogin_recv : %d\r\n%s\r\n" , ret, recBuf);
  1033. else
  1034. {
  1035. printf("\r\nlogin_recv : %d\r\n" , ret);
  1036. for(i = 0; i < ret; i++)
  1037. printf("%.2X ", recBuf[i]);
  1038. printf("\r\n");
  1039. }
  1040. }
  1041. // #endif
  1042. }
  1043. else if(ret <= 0)
  1044. ;
  1045. if(++timeOut > WEBSOCKET_LOGIN_RESPOND_TIMEOUT)
  1046. {
  1047. close(fd);
  1048. return -timeOut;
  1049. }
  1050. webSocket_delayms(1); //1ms
  1051. }
  1052. //
  1053. close(fd);
  1054. return -timeOut;
  1055. }
  1056. /*******************************************************************************
  1057. * 名称: webSocket_serverLinkToClient
  1058. * 功能: 服务器回复客户端的连接请求, 以建立websocket连接
  1059. * 形参: fd:连接句柄
  1060. * *recvBuf : 接收到来自客户端的数据(内含http连接请求)
  1061. * bufLen :
  1062. * 返回: >0 建立websocket连接成功 <=0 建立websocket连接失败
  1063. * 说明: 无
  1064. ******************************************************************************/
  1065. int webSocket_serverLinkToClient(int fd, char *recvBuf, int bufLen)
  1066. {
  1067. char *p;
  1068. int ret;
  1069. char recvShakeKey[512], respondPackage[1024];
  1070. if((p = strstr(recvBuf, "Sec-WebSocket-Key: ")) == NULL)
  1071. return -1;
  1072. p += strlen("Sec-WebSocket-Key: ");
  1073. //
  1074. memset(recvShakeKey, 0, sizeof(recvShakeKey));
  1075. sscanf(p, "%s", recvShakeKey); // 取得握手key
  1076. ret = strlen(recvShakeKey);
  1077. if(ret < 1)
  1078. return -1;
  1079. //
  1080. memset(respondPackage, 0, sizeof(respondPackage));
  1081. webSocket_buildHttpRespond((unsigned char *)recvShakeKey, (unsigned int)ret, respondPackage);
  1082. //
  1083. return send(fd, respondPackage, strlen(respondPackage), MSG_NOSIGNAL);
  1084. }
  1085. /*******************************************************************************
  1086. * 名称: webSocket_send
  1087. * 功能: websocket数据基本打包和发送
  1088. * 形参: fd:连接句柄
  1089. * *data : 数据
  1090. * dataLen : 长度
  1091. * isMask : 数据是否使用掩码, 客户端到服务器必须使用掩码模式
  1092. * type : 数据要要以什么识别头类型发送(txt, bin, ping, pong ...)
  1093. * 返回: 调用send的返回
  1094. * 说明: 无
  1095. ******************************************************************************/
  1096. int webSocket_send(int fd, char *data, int dataLen, bool isMask, WebsocketData_Type type)
  1097. {
  1098. unsigned char *webSocketPackage = NULL;
  1099. int retLen, ret;
  1100. #ifdef WEBSOCKET_DEBUG
  1101. unsigned int i;
  1102. printf("webSocket_send : %d\r\n", dataLen);
  1103. #endif
  1104. //---------- websocket数据打包 ----------
  1105. webSocketPackage = (unsigned char *)calloc(dataLen + 128, sizeof(char));
  1106. retLen = webSocket_enPackage((unsigned char *)data, dataLen, webSocketPackage, (dataLen + 128), isMask, type);
  1107. //显示数据
  1108. #ifdef WEBSOCKET_DEBUG
  1109. printf("webSocket_send : %d\r\n" , retLen);
  1110. for(i = 0; i < retLen; i ++)
  1111. printf("%.2X ", webSocketPackage[i]);
  1112. printf("\r\n");
  1113. #endif
  1114. //
  1115. printf("webSocket_send : %d\r\n" , retLen);
  1116. ret = send(fd, webSocketPackage, retLen, MSG_NOSIGNAL);
  1117. free(webSocketPackage);
  1118. return ret;
  1119. }
  1120. /*******************************************************************************
  1121. * 名称: webSocket_recv
  1122. * 功能: websocket数据接收和基本解包
  1123. * 形参: fd:连接句柄
  1124. * *data : 数据接收地址
  1125. * dataMaxLen : 接收区可用最大长度
  1126. * 返回: = 0 没有收到有效数据 > 0 成功接收并解包数据 < 0 非包数据的长度
  1127. * 说明: 无
  1128. ******************************************************************************/
  1129. int webSocket_recv(int fd, char *data, int dataMaxLen, WebsocketData_Type *dataType)
  1130. {
  1131. unsigned char *webSocketPackage = NULL, *recvBuf = NULL;
  1132. int ret, dpRet = WDT_NULL, retTemp, retFinal = 0;
  1133. int retLen = 0, retHeadLen = 0;
  1134. //
  1135. int timeOut = 0; //续传时,等待下一包需加时间限制
  1136. recvBuf = (unsigned char *)calloc(dataMaxLen, sizeof(char));
  1137. ret = recv(fd, recvBuf, dataMaxLen, MSG_NOSIGNAL);
  1138. //数据可能超出了范围限制
  1139. if(ret == dataMaxLen)
  1140. printf("webSocket_recv : warning !! recv buff too large !! (recv/%d)\r\n", ret);
  1141. //
  1142. if(ret > 0)
  1143. {
  1144. //---------- websocket数据解包 ----------
  1145. webSocketPackage = (unsigned char *)calloc(ret + 128, sizeof(char));
  1146. dpRet = webSocket_dePackage(recvBuf, ret, webSocketPackage, (ret + 128), (unsigned int *)&retLen, (unsigned int *)&retHeadLen);
  1147. if(dpRet == WDT_ERR && retLen == 0) //非包数据
  1148. {
  1149. memset(data, 0, dataMaxLen);
  1150. if(ret < dataMaxLen)
  1151. {
  1152. memcpy(data, recvBuf, ret);
  1153. retFinal = -ret;
  1154. }
  1155. else
  1156. {
  1157. memcpy(data, recvBuf, dataMaxLen);
  1158. retFinal = -dataMaxLen;
  1159. }
  1160. }
  1161. else //正常收包
  1162. {
  1163. //数据可能超出了范围限制
  1164. if(retLen > dataMaxLen)
  1165. {
  1166. printf("webSocket_recv : warning !! recv package too large !! (recvPackage/%d)\r\n", retLen);
  1167. goto recv_return_null;
  1168. }
  1169. //显示数据包的头10个字节
  1170. #ifdef WEBSOCKET_DEBUG
  1171. if(ret > 10)
  1172. printf("webSocket_recv : ret/%d, dpRet/%d, retLen/%d, head/%d : %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X\r\n",
  1173. ret, dpRet, retLen, retHeadLen,
  1174. recvBuf[0], recvBuf[1], recvBuf[2], recvBuf[3], recvBuf[4],
  1175. recvBuf[5], recvBuf[6], recvBuf[7], recvBuf[8], recvBuf[9]);
  1176. #endif
  1177. //续传? 检查数据包的头10个字节发现recv()时并没有把一包数据接收完,继续接收..
  1178. if(ret < retHeadLen + retLen)
  1179. {
  1180. timeOut = 50;//50*10=500ms等待
  1181. while(ret < retHeadLen + retLen)
  1182. {
  1183. webSocket_delayms(10);
  1184. retTemp = recv(fd, &recvBuf[ret], dataMaxLen - ret, MSG_NOSIGNAL);
  1185. if(retTemp > 0){
  1186. timeOut = 50;//50*10=500ms等待
  1187. ret += retTemp;
  1188. }else{
  1189. if(errno == EAGAIN || errno == EINTR);//连接中断
  1190. else goto recv_return_null;
  1191. }
  1192. if(--timeOut < 1)
  1193. goto recv_return_null;
  1194. }
  1195. //再解包一次
  1196. free(webSocketPackage);
  1197. webSocketPackage = (unsigned char *)calloc(ret + 128, sizeof(char));
  1198. dpRet = webSocket_dePackage(recvBuf, ret, webSocketPackage, (ret + 128), (unsigned int *)&retLen, (unsigned int *)&retHeadLen);
  1199. //
  1200. if(ret > 10)
  1201. printf("webSocket_recv : ret/%d, dpRet/%d, retLen/%d, head/%d : %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X\r\n",
  1202. ret, dpRet, retLen, retHeadLen,
  1203. recvBuf[0], recvBuf[1], recvBuf[2], recvBuf[3], recvBuf[4],
  1204. recvBuf[5], recvBuf[6], recvBuf[7], recvBuf[8], recvBuf[9]);
  1205. }
  1206. //
  1207. if(retLen > 0)
  1208. {
  1209. if(dpRet == WDT_PING)
  1210. {
  1211. webSocket_send(fd, (char *)webSocketPackage, retLen, true, WDT_PONG);//自动 ping-pong
  1212. // 显示数据
  1213. printf("webSocket_recv : PING %d\r\n%s\r\n" , retLen, webSocketPackage);
  1214. }
  1215. else if(dpRet == WDT_PONG)
  1216. {
  1217. printf("webSocket_recv : PONG %d\r\n%s\r\n" , retLen, webSocketPackage);
  1218. }
  1219. else //if(dpRet == WDT_TXTDATA || dpRet == WDT_BINDATA || dpRet == WDT_MINDATA)
  1220. {
  1221. memcpy(data, webSocketPackage, retLen);
  1222. // 显示数据
  1223. #ifdef WEBSOCKET_DEBUG
  1224. if(webSocketPackage[0] >= ' ' && webSocketPackage[0] <= '~')
  1225. printf("\r\nwebSocket_recv : New Package StrFile dpRet:%d/retLen:%d\r\n%s\r\n" , dpRet, retLen, webSocketPackage);
  1226. else
  1227. {
  1228. printf("\r\nwebSocket_recv : New Package BinFile dpRet:%d/retLen:%d\r\n" , dpRet, retLen);
  1229. int i;
  1230. for(i = 0; i < retLen; i++)
  1231. printf("%.2X ", webSocketPackage[i]);
  1232. printf("\r\n");
  1233. }
  1234. #endif
  1235. }
  1236. //
  1237. retFinal = retLen;
  1238. }
  1239. #ifdef WEBSOCKET_DEBUG
  1240. else
  1241. {
  1242. // 显示数据
  1243. if(recvBuf[0] >= ' ' && recvBuf[0] <= '~')
  1244. printf("\r\nwebSocket_recv : ret:%d/dpRet:%d/retLen:%d\r\n%s\r\n" , ret, dpRet, retLen, recvBuf);
  1245. else
  1246. {
  1247. printf("\r\nwebSocket_recv : ret:%d/dpRet:%d/retLen:%d\r\n%s\r\n" , ret, dpRet, retLen, recvBuf);
  1248. int i;
  1249. for(i = 0; i < ret; i++)
  1250. printf("%.2X ", recvBuf[i]);
  1251. printf("\r\n");
  1252. }
  1253. }
  1254. #endif
  1255. }
  1256. }
  1257. if(recvBuf) free(recvBuf);
  1258. if(webSocketPackage) free(webSocketPackage);
  1259. if(dataType) *dataType = dpRet;
  1260. return retFinal;
  1261. recv_return_null:
  1262. if(recvBuf) free(recvBuf);
  1263. if(webSocketPackage) free(webSocketPackage);
  1264. if(dataType) *dataType = dpRet;
  1265. return 0;
  1266. }
  1267. int main(void)
  1268. {
  1269. int ret, timeCount = 0;
  1270. int fd;
  1271. char buff[10240];
  1272. int pid;
  1273. //
  1274. pid = getpid();
  1275. printf("\r\n========== client(%d) start ! ==========\r\n\r\n", pid);
  1276. //
  1277. //netCheck_getIP("eth0", ip);
  1278. printf("\r\n========== ip(%s) port(%d) ! ==========\r\n\r\n", ip,port);
  1279. if((fd = webSocket_clientLinkToServer(ip, port, "/null")) <= 0)
  1280. {
  1281. printf("client link to server failed !\r\n");
  1282. return -1;
  1283. }
  1284. webSocket_delayms(100);
  1285. //
  1286. memset(buff, 0, sizeof(buff));
  1287. sprintf(buff, "tts1.pcm");
  1288. webSocket_send(fd, buff, strlen(buff), true, WDT_TXTDATA);
  1289. FILE * fid = fopen(buff,"r");
  1290. if(fid == NULL)
  1291. {
  1292. printf("打开%s失败","tts1.pcm");
  1293. return;
  1294. }
  1295. //
  1296. char line[1024*3];
  1297. int read_len = 0;
  1298. int rea_size = 0;
  1299. do
  1300. {
  1301. read_len = 0;
  1302. memset(line,0,1024);
  1303. int file_size = 0;
  1304. //获取文件大小
  1305. fseek (fid , 0 , SEEK_END);
  1306. long lSize = ftell (fid);
  1307. rewind (fid);
  1308. printf("file lSize %d\n", lSize); //输出
  1309. bool blastMsg = false;
  1310. while(lSize > file_size )
  1311. {
  1312. if(lSize -file_size < 1024*2 ){
  1313. read_len = lSize -file_size;
  1314. blastMsg = true;
  1315. printf("get last zhen size:%d\n",read_len);
  1316. }
  1317. else
  1318. {
  1319. read_len = 1024*2;
  1320. }
  1321. rea_size = fread(line,sizeof(char),read_len,fid);
  1322. //read_len = fgets(line,1024*2,fid);
  1323. printf("file size :%d;read size :%d\n",file_size, rea_size); //输出
  1324. sleep(1);
  1325. if(file_size == 0){
  1326. ret = webSocket_send(fd, line, rea_size, true, 100);
  1327. }
  1328. else if(blastMsg){
  1329. printf("send last websocket msg :strlen%d;read size :%d\n",strlen(line), rea_size); //输出
  1330. ret = webSocket_send(fd, line, rea_size, false, 99);
  1331. }
  1332. else{
  1333. ret = webSocket_send(fd, line, rea_size, false, WDT_MINDATA);
  1334. }
  1335. //strcpy(buff, "123");//即使ping包也要带点数据
  1336. // webSocket_send(fd,buff , strlen(buff), true, WDT_TXTDATA);
  1337. file_size += rea_size;
  1338. if(ret > 0)
  1339. {
  1340. printf("client(%d) send : %d\r\n", pid, file_size);
  1341. }
  1342. else // 检查错误, 是否连接已断开
  1343. {
  1344. printf("client() send failure.\r\n");
  1345. if(errno == EAGAIN || errno == EINTR)
  1346. ;
  1347. else
  1348. {
  1349. close(fd);
  1350. break;
  1351. }
  1352. }
  1353. }
  1354. fclose(fid);
  1355. //
  1356. /*memset(buff, 0, sizeof(buff));
  1357. ret = webSocket_recv(fd, buff, sizeof(buff), NULL);
  1358. if(ret > 0)
  1359. {
  1360. //===== 与服务器的应答 =====
  1361. printf("client(%d) recv : %s\r\n", pid, buff);
  1362. //
  1363. if(strstr(buff, "Hi~") != NULL)
  1364. {
  1365. memset(buff, 0, sizeof(buff));
  1366. sprintf(buff, "I am client(%d)", pid);
  1367. ret = webSocket_send(fd, buff, strlen(buff), true, WDT_TXTDATA);
  1368. }
  1369. else
  1370. ;
  1371. // ......
  1372. // ...
  1373. // send返回异常, 连接已断开
  1374. if(ret <= 0)
  1375. {
  1376. close(fd);
  1377. break;
  1378. }
  1379. }
  1380. else // 检查错误, 是否连接已断开
  1381. {
  1382. if(errno == EAGAIN || errno == EINTR)
  1383. ;
  1384. else
  1385. {
  1386. close(fd);
  1387. break;
  1388. }
  1389. }*/
  1390. //===== 3s客户端心跳 =====
  1391. if(timeCount > 3000)
  1392. {
  1393. timeCount = 10;
  1394. //
  1395. memset(buff, 0, sizeof(buff));
  1396. // sprintf(buff, "heart from client(%d)", pid);
  1397. // ret = webSocket_send(fd, buff, strlen(buff), true, WDT_TXTDATA);
  1398. strcpy(buff, "123");//即使ping包也要带点数据
  1399. ret = webSocket_send(fd, buff, strlen(buff), true, WDT_PING); //使用ping包代替心跳
  1400. if(ret <= 0)
  1401. {
  1402. close(fd);
  1403. break;
  1404. }
  1405. }
  1406. else
  1407. timeCount += 10;
  1408. //
  1409. webSocket_delayms(10);
  1410. }while(0);
  1411. printf("client close !\r\n");
  1412. return 0;
  1413. }

从程序可以看到,发送端在发送数据前首先给待发送数据添加了websocket协议首部,数据进行了异或掩码处理。

接收端在收到这个数据之后,首先需要读取首部解析,拿到实际帧数据长度,然后再继续读取数据,并判断数据满帧时,开始解析数据,即实现了组包和拆包的操作。不论客户端消息时满帧、粘包、拆包场景,服务端只有读取数据大于满帧时,在解析数据;如果数据未解析完,那剩余的数据则时下一帧数据,重复判断数据是否满帧。

程序如下:

  1. #include <unistd.h>
  2. #include "websocket_handler.h"
  3. #include <stdio.h>
  4. #include <string.h>
  5. #define DEBUG_LOG printf
  6. #define BUFFLEN 2048
  7. Websocket_Handler::Websocket_Handler(int fd):
  8. buff_(),
  9. status_(WEBSOCKET_UNCONNECT),
  10. header_map_(),
  11. fd_(fd),
  12. request_(new Websocket_Request),
  13. buff_len(0),
  14. handle(NULL)
  15. {
  16. //channel->setReadhandler(bind(&Http_conn::parse,this));
  17. }
  18. Websocket_Handler::Websocket_Handler(int fd, SP_Channel Channel):
  19. buff_(),
  20. status_(WEBSOCKET_UNCONNECT),
  21. header_map_(),
  22. fd_(fd),
  23. request_(new Websocket_Request),
  24. channel(Channel),
  25. buff_out(),
  26. buff_len(0),
  27. handle(NULL),
  28. m_nOffset(0),
  29. buff_cache()
  30. {
  31. channel->setReadhandler(bind(&Websocket_Handler::handlerconn,this));
  32. }
  33. Websocket_Handler::~Websocket_Handler(){
  34. //add by cy
  35. delete request_;
  36. }
  37. void inverted_string(char *str,int len)
  38. {
  39. int i; char temp;
  40. for (i=0;i<len/2;++i)
  41. {
  42. temp = *(str+i);
  43. *(str+i) = *(str+len-i-1);
  44. *(str+len-i-1) = temp;
  45. }
  46. }
  47. int Websocket_Handler::recv_request()
  48. {
  49. printf("Websocket_Handler::recv_request: recv request logic.\n");
  50. char readCache[1024*4] = {0};
  51. int recvsize;
  52. int head_len = 0;
  53. do{
  54. recvsize = 0;
  55. recvsize = read(fd_,readCache,BUFFLEN);
  56. printf("read:size:%d,curslot:%d.\n",recvsize,m_nOffset);
  57. if (recvsize < 0)
  58. {
  59. memset(readCache, 0, sizeof(readCache));
  60. printf("read failure,wait next frame websocket.\n");
  61. return 0;
  62. }else if( 0 == recvsize ){
  63. if( NULL != handle ){
  64. fclose(handle);
  65. }
  66. channel->setDeleted(true);
  67. channel->getLoop().lock()->addTimer(channel,0);
  68. return 0;
  69. }
  70. memcpy(buff_+m_nOffset, readCache, recvsize);
  71. m_nOffset = m_nOffset + recvsize;//set offset
  72. //获取消息头
  73. if( 0 > (head_len = getFrameHeaderInfo(buff_,&header_msg,m_nOffset)) )
  74. {
  75. printf("error is not full frame.\n");
  76. continue;
  77. }
  78. printf("read frame head\tFIN: %d\tOPCODE: %d\tMASK: %d\tPAYLOADLEN: %d\tHeadlen:%d\n.",
  79. header_msg.fin, header_msg.opcode, header_msg.mask, header_msg.payload_length,head_len);
  80. //读取满帧数据校验
  81. if(header_msg.payload_length > m_nOffset- head_len || header_msg.payload_length <= 0 )
  82. {
  83. continue;
  84. }
  85. if( 1 ==header_msg.mask){
  86. umask(buff_+head_len,header_msg.payload_length,header_msg.masking_key);
  87. }
  88. switch(header_msg.opcode){
  89. case 0x00:
  90. printf("recv mid frame.\n");
  91. break;
  92. case 0x01:
  93. {
  94. printf("recv text frame.\n\t%s\n",(buff_+head_len));
  95. if( handle == NULL && header_msg.payload_length <= 1000){
  96. char filename[1024];
  97. sprintf(filename,"./snOfflineVoice_%s.snv",buff_+head_len);
  98. handle = fopen(filename,"a+");
  99. }
  100. m_nOffset = m_nOffset - header_msg.payload_length - head_len;
  101. char buffer[2048*2] = {0};
  102. memcpy(buffer, buff_+header_msg.payload_length+head_len,m_nOffset);
  103. memset(buff_,0,BUFFLEN*2);
  104. memcpy(buff_, buffer,m_nOffset);
  105. return 0;
  106. }
  107. case 0x02:
  108. printf("recv bin frame.\n");
  109. if( handle == NULL){
  110. char filename[1024];
  111. sprintf(filename,"./snOfflineVoice_%02d.snv",header_msg.payload_length);
  112. handle = fopen(filename,"a+");
  113. }
  114. break;
  115. case 0x08:
  116. channel->setDeleted(true);
  117. channel->getLoop().lock()->addTimer(channel,0);
  118. return 0;
  119. case 0x09:
  120. printf("recv ping frame,need send pong frame.\n");
  121. //webSocket_send(fd, (char *)webSocketPackage, retLen, true, WDT_PONG);//自动 ping-pong
  122. return 0;
  123. case 0x0A:
  124. printf("recv pong frame.\n");
  125. return 0;
  126. default:
  127. printf("recv unknow frame.\n");
  128. }
  129. //just one frame or frist of mutl_frame
  130. /*if( (1 ==header_msg.fin && 0 < header_msg.opcode && 3 > header_msg.opcode && handle != NULL )
  131. || (0 ==header_msg.fin && 0 !=header_msg.opcode && 3 > header_msg.opcode ) ){
  132. char filename[1024];
  133. sprintf(filename,"./snOfflineVoice_%02d.snv",header_msg.payload_length);
  134. handle = fopen(filename,"a+");
  135. if(NULL != handle){
  136. fwrite(buff_+head_len, sizeof(char), header_msg.payload_length, handle);
  137. fflush(handle);
  138. printf("fwrite:size:%d,payload_len:%d.\n",header_msg.payload_length,header_msg.payload_length);
  139. m_nOffset = m_nOffset - header_msg.payload_length - head_len;
  140. char swap[2048] = {0};
  141. memcpy(swap, buff_+header_msg.payload_length+head_len,m_nOffset);
  142. memset(buff_,0,BUFFLEN*2);
  143. memcpy(buff_, swap,m_nOffset);
  144. return 0;//break function
  145. }
  146. }*/
  147. if( NULL != handle){
  148. fwrite(buff_+head_len, sizeof(char), header_msg.payload_length, handle);
  149. fflush(handle);
  150. m_nOffset = m_nOffset - header_msg.payload_length - head_len;
  151. char swap[2048*2] = {0};
  152. memcpy(swap, buff_+header_msg.payload_length+head_len,m_nOffset);
  153. memset(buff_,0,BUFFLEN*2);
  154. memcpy(buff_, swap,m_nOffset);
  155. printf("fwrite:size:%d,m_nOffset:%d.\n",header_msg.payload_length, m_nOffset);
  156. }
  157. if(m_nOffset > 4){
  158. memset(&header_msg,0,sizeof(header_msg));
  159. printf(">>>>>>>>>>check Incomming data frame<<<<<<<<<.\n");
  160. if( 0 > (head_len = getFrameHeaderInfo(buff_,&header_msg,m_nOffset)) )
  161. {
  162. printf("error is not full frame.\n");
  163. continue;
  164. }
  165. if(header_msg.payload_length <= m_nOffset- head_len&& header_msg.payload_length > 0 )
  166. {
  167. printf("read frame head\tFIN: %d\tOPCODE: %d\tMASK: %d\tPAYLOADLEN: %d\tHeadlen:%d.\n",
  168. header_msg.fin, header_msg.opcode, header_msg.mask, header_msg.payload_length,head_len);
  169. if( 1 ==header_msg.mask){
  170. umask(buff_+head_len,header_msg.payload_length,header_msg.masking_key);
  171. }
  172. fwrite(buff_+head_len, sizeof(char), header_msg.payload_length, handle);
  173. fflush(handle);
  174. printf("fwrite more frame:size:%d,m_nOffset:%d.\n",header_msg.payload_length, m_nOffset);
  175. m_nOffset = m_nOffset -header_msg.payload_length-head_len;
  176. char swap[2018] = {0};
  177. memcpy(swap, buff_+header_msg.payload_length+head_len,m_nOffset);
  178. memset(buff_,0,BUFFLEN*2);
  179. memcpy(buff_, swap,m_nOffset);
  180. }
  181. else{
  182. printf(" Lack of data, need read more data.\n");
  183. continue;
  184. }
  185. }
  186. if(1 == header_msg.fin && NULL != handle &&
  187. ( 0 == header_msg.opcode || 2 == header_msg.opcode) ){
  188. fclose(handle);
  189. handle = NULL;
  190. m_nOffset = 0;
  191. memset(buff_,0,BUFFLEN*2);
  192. printf("is last frame, need close file.\n");
  193. return 0;
  194. }
  195. printf("read data again.\n");
  196. }while(1);
  197. printf("wait next request websocket .\n");
  198. return 0;
  199. }
  200. int Websocket_Handler::getFrameHeaderInfo(char *buff,frame_head* head,int curSize)
  201. {
  202. char one_char;
  203. int head_len = 0;
  204. one_char = buff[0];
  205. head->fin = (one_char & 0x80) == 0x80;
  206. head->opcode = one_char & 0x0F;
  207. one_char = buff[1];
  208. head->mask = (one_char & 0x80) == 0X80;
  209. /*get payload length*/
  210. head->payload_length = one_char & 0x7F;
  211. if (head->payload_length == 126)
  212. {
  213. char extern_len[2];
  214. extern_len[0] = buff[2];
  215. extern_len[1] = buff[3];
  216. head->payload_length = (extern_len[0]&0xFF) << 8 | (extern_len[1]&0xFF);
  217. head_len = 4;
  218. }
  219. else if (head->payload_length == 127)
  220. {
  221. char extern_len[8];
  222. //wait to doing
  223. //...
  224. inverted_string(extern_len,8);
  225. memcpy(&(head->payload_length),extern_len,8);
  226. head_len = 10;
  227. }
  228. else if(head->payload_length == 0)
  229. {
  230. printf("read payload_length is 0,close connect.");
  231. return -1;
  232. }
  233. else if(head->payload_length < 126)
  234. {
  235. printf("read payload_length is less 126, is little frame.\n");
  236. head_len = 2;
  237. }
  238. if(head->mask ==1 ){
  239. if(curSize <= 7 )
  240. {
  241. printf("check buff size error.\n");
  242. return -1;
  243. }
  244. head->masking_key[0] = buff[head_len+0];
  245. head->masking_key[1] = buff[head_len+1];
  246. head->masking_key[2] = buff[head_len+2];
  247. head->masking_key[3] = buff[head_len+3];
  248. return head_len +4;
  249. }
  250. return head_len;
  251. }
  252. int Websocket_Handler::handlerconn(){
  253. if(status_ == WEBSOCKET_UNCONNECT){
  254. int len = read(fd_,buff_,BUFFLEN*2);
  255. if (len<=0)
  256. return -1;
  257. return handshark();
  258. }
  259. printf("Websocket_Handler::handlerconn: begin handlerconn logic.\n");
  260. recv_request();
  261. return 0;
  262. //int ilenData = 0;
  263. //request_->getReqData(buff_out,buff_len);
  264. snprintf(buff_out,2048,"%s",buff_);
  265. //send_frame_head();
  266. //request_->print();
  267. //respond client
  268. channel->setRevents(EPOLLOUT|EPOLLET);
  269. channel->getLoop().lock()->updatePoller(channel);
  270. channel->setWritehandler(bind(&Websocket_Handler::send_respond,this));
  271. printf("process logic end.\n");
  272. memset(buff_, 0, sizeof(buff_));
  273. return 0;
  274. }
  275. int Websocket_Handler::handshark(){
  276. char request[1024] = {};
  277. status_ = WEBSOCKET_HANDSHARKED;
  278. fetch_http_info();
  279. parse_str(request);
  280. printf("the respone is %s\n",request);
  281. memset(buff_, 0, sizeof(buff_));
  282. return send_data(request);
  283. }
  284. char * Websocket_Handler::packData(const char * message,unsigned long * len)
  285. {
  286. char * data=NULL;
  287. unsigned long n;
  288. n=strlen(message);
  289. if (n < 126)
  290. {
  291. data=(char *)malloc(n+2);
  292. memset(data,0,n+2);
  293. data[0] = 0x81;
  294. data[1] = n;
  295. memcpy(data+2,message,n);
  296. *len=n+2;
  297. }
  298. else if (n < 0xFFFF)
  299. {
  300. data=(char *)malloc(n+4);
  301. memset(data,0,n+4);
  302. data[0] = 0x81;
  303. data[1] = 126;
  304. data[2] = (n>>8 & 0xFF);
  305. data[3] = (n & 0xFF);
  306. memcpy(data+4,message,n);
  307. *len=n+4;
  308. }
  309. else
  310. {
  311. // 暂不处理超长内容
  312. data=(char *)malloc(n+10);//给data分配内存
  313. if (NULL == data) {//判断data是否为NULL
  314. printf("data is NULL.\n");
  315. return NULL;
  316. }
  317. memset(data,0,n+10);//重置data为0
  318. data[0] = 0x81;//设置第0-7位为1000 0001(FIN为1,Opcode为1)
  319. data[1] = 127;//设置第8-15位为0111 1111
  320. data[2] = (n>>56 & 0xFF);//设置第16-23位为n-128(将n右移8位在与1111 1111做与运算)
  321. data[3] = (n>>48 & 0xFF);//设置第24-31位为n-128(将n右移8位在与1111 1111做与运算)
  322. data[4] = (n>>40 & 0xFF);//设置第32-39位为n-128(将n右移8位在与1111 1111做与运算)
  323. data[5] = (n>>32 & 0xFF);//设置第40-47位为n-128(将n右移8位在与1111 1111做与运算)
  324. data[6] = (n>>24 & 0xFF);//设置第48-55位为n-128(将n右移8位在与1111 1111做与运算)
  325. data[7] = (n>>16 & 0xFF);//设置第56-63位为n-128(将n右移8位在与1111 1111做与运算)
  326. data[8] = (n>>8 & 0xFF);//设置第64-71位为n-128(将n右移8位在与1111 1111做与运算)
  327. data[9] = (n & 0xFF);//设置第72-79位为n的右8(0-7)位
  328. memcpy(data+10,message,n); //将message添加到第10个字节之后
  329. *len=n+10;
  330. }
  331. return data;
  332. }
  333. int Websocket_Handler::send_respond()
  334. {
  335. printf("recive:%s,len:%d.\n",buff_out,buff_len);
  336. char * respData;
  337. unsigned long respLen = buff_len;
  338. respData=packData(buff_out,&respLen);
  339. printf("packData:%s,len:%d.\n",respData,respLen);
  340. if( !respData || respLen <= 0 )
  341. {
  342. printf("data is empty!\n");
  343. return -1;
  344. }
  345. //umask(buff_out,buff_len,request_->getMaskKey());
  346. //printf("send:%s.\n",buff_out);
  347. int len = write(fd_, respData, respLen);
  348. free(respData);
  349. channel->setRevents(EPOLLIN|EPOLLET);
  350. channel->getLoop().lock()->updatePoller(channel);
  351. return len;
  352. }
  353. void Websocket_Handler::parse_str(char *request){
  354. strcat(request, "HTTP/1.1 101 Switching Protocols\r\n");
  355. strcat(request, "Connection: upgrade\r\n");
  356. strcat(request, "Sec-WebSocket-Accept: ");
  357. std::string server_key = header_map_["Sec-WebSocket-Key"];
  358. server_key += MAGIC_KEY;
  359. SHA1 sha;
  360. unsigned int message_digest[5];
  361. sha.Reset();
  362. sha << server_key.c_str();
  363. sha.Result(message_digest);
  364. for (int i = 0; i < 5; i++) {
  365. message_digest[i] = htonl(message_digest[i]);
  366. }
  367. server_key = base64_encode(reinterpret_cast<const unsigned char*>(message_digest),20);
  368. server_key += "\r\n";
  369. strcat(request, server_key.c_str());
  370. strcat(request, "Upgrade: websocket\r\n\r\n");
  371. }
  372. int Websocket_Handler::fetch_http_info(){
  373. std::istringstream s(buff_);
  374. std::string request;
  375. std::getline(s, request);
  376. if (request[request.size()-1] == '\r') {
  377. request.erase(request.end()-1);
  378. } else {
  379. return -1;
  380. }
  381. std::string header;
  382. std::string::size_type end;
  383. while (std::getline(s, header) && header != "\r") {
  384. if (header[header.size()-1] != '\r') {
  385. continue; //end
  386. } else {
  387. header.erase(header.end()-1);//remove last char
  388. }
  389. end = header.find(": ",0);
  390. if (end != std::string::npos) {
  391. std::string key = header.substr(0,end);
  392. std::string value = header.substr(end+2);
  393. header_map_[key] = value;
  394. }
  395. }
  396. return 0;
  397. }
  398. int Websocket_Handler::send_data(char *buff){
  399. return write(fd_, buff, strlen(buff));
  400. }
  401. int Websocket_Handler::send_frame_head()
  402. {
  403. char *response_head;
  404. int head_length = 0;
  405. if(buff_len<126)
  406. {
  407. response_head = (char*)malloc(2);
  408. response_head[0] = 0x81;
  409. response_head[1] = buff_len;
  410. head_length = 2;
  411. }
  412. else if (buff_len<0xFFFF)
  413. {
  414. response_head = (char*)malloc(4);
  415. response_head[0] = 0x81;
  416. response_head[1] = 126;
  417. response_head[2] = (buff_len >> 8 & 0xFF);
  418. response_head[3] = (buff_len & 0xFF);
  419. head_length = 4;
  420. }
  421. else
  422. {
  423. //no code
  424. response_head = (char*)malloc(12);
  425. // response_head[0] = 0x81;
  426. // response_head[1] = 127;
  427. // response_head[2] = (head->payload_length >> 8 & 0xFF);
  428. // response_head[3] = (head->payload_length & 0xFF);
  429. head_length = 12;
  430. }
  431. if(write(fd_,response_head,buff_len)<=0)
  432. {
  433. perror("write head");
  434. return -1;
  435. }
  436. free(response_head);
  437. return 0;
  438. }
  439. void Websocket_Handler::umask(char *data,int len,char *mask)
  440. {
  441. int i;
  442. for (i=0;i<len;++i){
  443. *(data+i) ^= *(mask+(i%4));
  444. }
  445. }

我在测试的时候采用的是两台机器,客户端读取音频文件,每次固定2K连续发送数据,最有一帧不足2K场景。

所以在测试的时候会发现服务器端收到的数据包现象如下:

第一次接收一个整包2K

中间接收数据有半包、有满包情况;还有一次读取两帧数据的场景,这时在处理完一帧数据时,再判断是否还粘着的下一帧数据,并校验数据是否时满帧,如果不是,再继续read,直到满帧,解析数据。

(0)

相关推荐