TCP常用拆包处理

Posted linxmouse

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP常用拆包处理相关的知识,希望对你有一定的参考价值。

1.演示环境为windows 10 1903

2.演示代码

  1 #include "pch.h"
  2 #include <iostream>
  3 #include <WinSock2.h>
  4 #include <WS2tcpip.h>
  5 
  6 #pragma comment(lib, "ws2_32.lib")
  7 
  8 #define BUFFER_LENGTH                256
  9 #define PACK_LENGTH                    11
 10 #define PACK_BUFFER_LENGTH            512
 11 
 12 int main()
 13 
 14     char pack_buffer[PACK_BUFFER_LENGTH] =  0 ;
 15     int pack_buffer_len = 0;
 16 
 17     WORD sv = MAKEWORD(2, 2);
 18     WSAData data;
 19     SOCKET client = INVALID_SOCKET;
 20 
 21     sockaddr_in addr;
 22     addr.sin_family = AF_INET;
 23     addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
 24     //addr.sin_addr.S_un.S_addr = InetPtonA(AF_INET, "127.0.0.1", NULL);
 25     addr.sin_port = htons(8080);
 26 
 27     while (true)
 28     
 29         while (true)
 30         
 31             if (WSAStartup(sv, &data) == 0)
 32             
 33                 client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 34                 if (client != INVALID_SOCKET)
 35                 
 36                     if (connect(client, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
 37                     
 38                         printf("connect error. reconnecting...\\n");
 39                         closesocket(client);
 40                         WSACleanup();
 41                         Sleep(1000);
 42                     
 43                     else 
 44                         const char *data = "message from client.\\n";
 45                         int ret = send(client, data, strlen(data), 0);
 46                         //int ret = send(client, "hello world.\\n", strlen("hello world.\\n"), 0);
 47                         printf("socket connected.\\n");
 48                         break;
 49                     
 50                 
 51                 else 
 52                     printf("invalid socket.\\n");
 53                 
 54             
 55         
 56 
 57         char buffer[255];
 58         while (true)
 59         
 60             int ret = recv(client, buffer, BUFFER_LENGTH, 0);
 61             if (ret > 0)
 62             
 63                 // 粘包情况
 64                 buffer[ret] = \\0;
 65                 printf(buffer);
 66 
 67                 // 1.数据包定长
 68                 //char pack[PACK_LENGTH] =  0 ;
 69                 //strncat(pack_buffer, buffer, ret);
 70                 //pack_buffer_len += ret;
 71                 //while (pack_buffer_len >= PACK_LENGTH)
 72                 //
 73                 //    strncpy(pack, pack_buffer, PACK_LENGTH);
 74                 //    char spack[PACK_LENGTH + 1] =  0 ;
 75                 //    strncpy(spack, pack, PACK_LENGTH);
 76                 //    spack[PACK_LENGTH] = ‘\\0‘;
 77                 //    printf("pack: %s;\\r\\n", spack);
 78 
 79                 //    pack_buffer_len -= PACK_LENGTH;
 80                 //    strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
 81                 //
 82 
 83                 // 2.消息头+消息体 消息头=消息头标识+长度
 84                 //strncat(pack_buffer, buffer, ret);
 85                 //char *pbrk = NULL;
 86                 //do
 87                 //
 88                 //    pbrk = strpbrk(pack_buffer, "\\r\\n");                
 89                 //    if (pbrk != NULL)
 90                 //    
 91                 //        int len = pbrk - pack_buffer;
 92                 //        // 去掉消息头+错误包数据
 93                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
 94                 //        len = pack_buffer[0];
 95                 //        char *pack = (char *)malloc(len + 1);
 96                 //        strncpy(pack, pack_buffer + 1, len);
 97                 //        pack[len] = ‘\\0‘;
 98                 //        printf("pack: %s;\\n", pack);
 99                 //        free(pack);
100                 //        strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
101                 //    
102                 // while (pbrk);
103 
104                 // 3.特殊字符作为消息结尾
105                 //strncat(pack_buffer, buffer, ret);
106                 //char *pbrk = NULL;
107                 //do
108                 //
109                 //    pbrk = strstr(pack_buffer, "\\r\\n");
110                 //    //pbrk = strpbrk(pack_buffer, "\\r\\n");
111                 //    if (pbrk != NULL)
112                 //    
113                 //        int len = pbrk - pack_buffer;
114                 //        char *pack = (char *)malloc(len + 1);
115                 //        strncpy(pack, pack_buffer, len);
116                 //        pack[len] = ‘\\0‘;
117                 //        printf("pack: %s;\\n", pack);
118                 //        free(pack);
119                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
120                 //    
121                 // while (pbrk);
122             
123             else if (ret == 0)
124             
125                 printf("Connection closed\\n");
126                 closesocket(client);
127                 WSACleanup();
128                 break;
129             
130             else
131             
132                 printf("recv failed: %d\\n", WSAGetLastError());
133                 closesocket(client);
134                 WSACleanup();
135                 break;
136             
137         
138     
139 
140     closesocket(client);
141     WSACleanup();
142 
143     return 0;
144 

3.不作拆包处理的情况

技术图片
 1 // 粘包情况
 2                 buffer[ret] = \\0;
 3                 printf(buffer);
 4 
 5                 // 1.数据包定长
 6                 //char pack[PACK_LENGTH] =  0 ;
 7                 //strncat(pack_buffer, buffer, ret);
 8                 //pack_buffer_len += ret;
 9                 //while (pack_buffer_len >= PACK_LENGTH)
10                 //
11                 //    strncpy(pack, pack_buffer, PACK_LENGTH);
12                 //    char spack[PACK_LENGTH + 1] =  0 ;
13                 //    strncpy(spack, pack, PACK_LENGTH);
14                 //    spack[PACK_LENGTH] = ‘\\0‘;
15                 //    printf("pack: %s;\\r\\n", spack);
16 
17                 //    pack_buffer_len -= PACK_LENGTH;
18                 //    strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
19                 //
20 
21                 // 2.消息头+消息体 消息头=消息头标识+长度
22                 //strncat(pack_buffer, buffer, ret);
23                 //char *pbrk = NULL;
24                 //do
25                 //
26                 //    pbrk = strpbrk(pack_buffer, "\\r\\n");                
27                 //    if (pbrk != NULL)
28                 //    
29                 //        int len = pbrk - pack_buffer;
30                 //        // 去掉消息头+错误包数据
31                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
32                 //        len = pack_buffer[0];
33                 //        char *pack = (char *)malloc(len + 1);
34                 //        strncpy(pack, pack_buffer + 1, len);
35                 //        pack[len] = ‘\\0‘;
36                 //        printf("pack: %s;\\n", pack);
37                 //        free(pack);
38                 //        strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
39                 //    
40                 // while (pbrk);
41 
42                 // 3.特殊字符作为消息结尾
43                 //strncat(pack_buffer, buffer, ret);
44                 //char *pbrk = NULL;
45                 //do
46                 //
47                 //    pbrk = strstr(pack_buffer, "\\r\\n");
48                 //    //pbrk = strpbrk(pack_buffer, "\\r\\n");
49                 //    if (pbrk != NULL)
50                 //    
51                 //        int len = pbrk - pack_buffer;
52                 //        char *pack = (char *)malloc(len + 1);
53                 //        strncpy(pack, pack_buffer, len);
54                 //        pack[len] = ‘\\0‘;
55                 //        printf("pack: %s;\\n", pack);
56                 //        free(pack);
57                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
58                 //    
59                 // while (pbrk);
View Code

使用sockettool连续发送一个字符串10次

技术图片

从输出结果可以看出数据包粘在了一块,出现了粘包

socket connected.
123456abc123456abc123456abc123456abc123456abc123456abc123456abc123456abc123456abc123456abc

4.使用定长数据包,数据包长度设定为11

技术图片
 1 // 粘包情况
 2                 //buffer[ret] = ‘\\0‘;
 3                 //printf(buffer);
 4 
 5                 // 1.数据包定长
 6                 char pack[PACK_LENGTH] =  0 ;
 7                 strncat(pack_buffer, buffer, ret);
 8                 pack_buffer_len += ret;
 9                 while (pack_buffer_len >= PACK_LENGTH)
10                 
11                     strncpy(pack, pack_buffer, PACK_LENGTH);
12                     char spack[PACK_LENGTH + 1] =  0 ;
13                     strncpy(spack, pack, PACK_LENGTH);
14                     spack[PACK_LENGTH] = \\0;
15                     printf("pack: %s;\\r\\n", spack);
16 
17                     pack_buffer_len -= PACK_LENGTH;
18                     strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
19                 
20 
21                 // 2.消息头+消息体 消息头=消息头标识+长度
22                 //strncat(pack_buffer, buffer, ret);
23                 //char *pbrk = NULL;
24                 //do
25                 //
26                 //    pbrk = strpbrk(pack_buffer, "\\r\\n");                
27                 //    if (pbrk != NULL)
28                 //    
29                 //        int len = pbrk - pack_buffer;
30                 //        // 去掉消息头+错误包数据
31                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
32                 //        len = pack_buffer[0];
33                 //        char *pack = (char *)malloc(len + 1);
34                 //        strncpy(pack, pack_buffer + 1, len);
35                 //        pack[len] = ‘\\0‘;
36                 //        printf("pack: %s;\\n", pack);
37                 //        free(pack);
38                 //        strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
39                 //    
40                 // while (pbrk);
41 
42                 // 3.特殊字符作为消息结尾
43                 //strncat(pack_buffer, buffer, ret);
44                 //char *pbrk = NULL;
45                 //do
46                 //
47                 //    pbrk = strstr(pack_buffer, "\\r\\n");
48                 //    //pbrk = strpbrk(pack_buffer, "\\r\\n");
49                 //    if (pbrk != NULL)
50                 //    
51                 //        int len = pbrk - pack_buffer;
52                 //        char *pack = (char *)malloc(len + 1);
53                 //        strncpy(pack, pack_buffer, len);
54                 //        pack[len] = ‘\\0‘;
55                 //        printf("pack: %s;\\n", pack);
56                 //        free(pack);
57                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
58                 //    
59                 // while (pbrk);
View Code

使用sockettool连续发送一个长度为11的数据包10次

技术图片

从输出结果可以看出对数据包按自己要求进行了拆包处理

socket connected.
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;
pack: 1234567890a;

5.使用消息头+消息体 消息头=消息头标识+长度

技术图片
 1 // 粘包情况
 2                 //buffer[ret] = ‘\\0‘;
 3                 //printf(buffer);
 4 
 5                 // 1.数据包定长
 6                 //char pack[PACK_LENGTH] =  0 ;
 7                 //strncat(pack_buffer, buffer, ret);
 8                 //pack_buffer_len += ret;
 9                 //while (pack_buffer_len >= PACK_LENGTH)
10                 //
11                 //    strncpy(pack, pack_buffer, PACK_LENGTH);
12                 //    char spack[PACK_LENGTH + 1] =  0 ;
13                 //    strncpy(spack, pack, PACK_LENGTH);
14                 //    spack[PACK_LENGTH] = ‘\\0‘;
15                 //    printf("pack: %s;\\r\\n", spack);
16 
17                 //    pack_buffer_len -= PACK_LENGTH;
18                 //    strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
19                 //
20 
21                 // 2.消息头+消息体 消息头=消息头标识+长度
22                 strncat(pack_buffer, buffer, ret);
23                 char *pbrk = NULL;
24                 do
25                 
26                     pbrk = strpbrk(pack_buffer, "\\r\\n");                
27                     if (pbrk != NULL)
28                     
29                         int len = pbrk - pack_buffer;
30                         // 去掉消息头+错误包数据
31                         strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
32                         len = pack_buffer[0];
33                         char *pack = (char *)malloc(len + 1);
34                         strncpy(pack, pack_buffer + 1, len);
35                         pack[len] = \\0;
36                         printf("pack: %s;\\n", pack);
37                         free(pack);
38                         strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
39                     
40                  while (pbrk);
41 
42                 // 3.特殊字符作为消息结尾
43                 //strncat(pack_buffer, buffer, ret);
44                 //char *pbrk = NULL;
45                 //do
46                 //
47                 //    pbrk = strstr(pack_buffer, "\\r\\n");
48                 //    //pbrk = strpbrk(pack_buffer, "\\r\\n");
49                 //    if (pbrk != NULL)
50                 //    
51                 //        int len = pbrk - pack_buffer;
52                 //        char *pack = (char *)malloc(len + 1);
53                 //        strncpy(pack, pack_buffer, len);
54                 //        pack[len] = ‘\\0‘;
55                 //        printf("pack: %s;\\n", pack);
56                 //        free(pack);
57                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
58                 //    
59                 // while (pbrk);
View Code

使用sockettool连续发送数据包 回车换行+长度5+字符串12345 10次

技术图片

从输出结果可以看出对数据包按自己要求进行了拆包处理

socket connected.
pack: 12345;
pack: 12345;
pack: 12345;
pack: 12345;
pack: 12345;
pack: 12345;
pack: 12345;
pack: 12345;
pack: 12345;
pack: 12345;

6.特殊字符作为消息结尾

技术图片
 1 // 粘包情况
 2                 //buffer[ret] = ‘\\0‘;
 3                 //printf(buffer);
 4 
 5                 // 1.数据包定长
 6                 //char pack[PACK_LENGTH] =  0 ;
 7                 //strncat(pack_buffer, buffer, ret);
 8                 //pack_buffer_len += ret;
 9                 //while (pack_buffer_len >= PACK_LENGTH)
10                 //
11                 //    strncpy(pack, pack_buffer, PACK_LENGTH);
12                 //    char spack[PACK_LENGTH + 1] =  0 ;
13                 //    strncpy(spack, pack, PACK_LENGTH);
14                 //    spack[PACK_LENGTH] = ‘\\0‘;
15                 //    printf("pack: %s;\\r\\n", spack);
16 
17                 //    pack_buffer_len -= PACK_LENGTH;
18                 //    strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
19                 //
20 
21                 // 2.消息头+消息体 消息头=消息头标识+长度
22                 //strncat(pack_buffer, buffer, ret);
23                 //char *pbrk = NULL;
24                 //do
25                 //
26                 //    pbrk = strpbrk(pack_buffer, "\\r\\n");                
27                 //    if (pbrk != NULL)
28                 //    
29                 //        int len = pbrk - pack_buffer;
30                 //        // 去掉消息头+错误包数据
31                 //        strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
32                 //        len = pack_buffer[0];
33                 //        char *pack = (char *)malloc(len + 1);
34                 //        strncpy(pack, pack_buffer + 1, len);
35                 //        pack[len] = ‘\\0‘;
36                 //        printf("pack: %s;\\n", pack);
37                 //        free(pack);
38                 //        strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
39                 //    
40                 // while (pbrk);
41 
42                 // 3.特殊字符作为消息结尾
43                 strncat(pack_buffer, buffer, ret);
44                 char *pbrk = NULL;
45                 do
46                 
47                     pbrk = strstr(pack_buffer, "\\r\\n");
48                     //pbrk = strpbrk(pack_buffer, "\\r\\n");
49                     if (pbrk != NULL)
50                     
51                         int len = pbrk - pack_buffer;
52                         char *pack = (char *)malloc(len + 1);
53                         strncpy(pack, pack_buffer, len);
54                         pack[len] = \\0;
55                         printf("pack: %s;\\n", pack);
56                         free(pack);
57                         strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
58                     
59                  while (pbrk);
View Code

使用sockettool连续发送数据包 123456789abc+回车换行 和 tcp粘包拆包常规处理+回车换行 10次

技术图片

从输出结果可以看出对数据包按自己要求进行了拆包处理

socket connected.
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;
pack: 123456789abc;
pack: tcp粘包拆包常规处理;

 

以上是关于TCP常用拆包处理的主要内容,如果未能解决你的问题,请参考以下文章

TCP粘包和拆包

TCP-缓冲区和粘包、拆包有啥关系?

十二.Netty入门到超神系列-TCP粘包拆包处理

TCP粘包拆包基本解决方案

高效的TCP数据拆包器

tcp粘包拆包