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...
");
 39                         closesocket(client);
 40                         WSACleanup();
 41                         Sleep(1000);
 42                     }
 43                     else {
 44                         const char *data = "message from client.
";
 45                         int ret = send(client, data, strlen(data), 0);
 46                         //int ret = send(client, "hello world.
", strlen("hello world.
"), 0);
 47                         printf("socket connected.
");
 48                         break;
 49                     }
 50                 }
 51                 else {
 52                     printf("invalid socket.
");
 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] = '';
 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] = '';
 77                 //    printf("pack: %s;
", 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, "
");                
 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] = '';
 98                 //        printf("pack: %s;
", 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, "
");
110                 //    //pbrk = strpbrk(pack_buffer, "
");
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] = '';
117                 //        printf("pack: %s;
", 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
");
126                 closesocket(client);
127                 WSACleanup();
128                 break;
129             }
130             else
131             {
132                 printf("recv failed: %d
", 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] = '';
 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] = '';
15                 //    printf("pack: %s;
", 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, "
");                
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] = '';
36                 //        printf("pack: %s;
", 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, "
");
48                 //    //pbrk = strpbrk(pack_buffer, "
");
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] = '';
55                 //        printf("pack: %s;
", 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] = '';
 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] = '';
15                     printf("pack: %s;
", 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, "
");                
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] = '';
36                 //        printf("pack: %s;
", 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, "
");
48                 //    //pbrk = strpbrk(pack_buffer, "
");
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] = '';
55                 //        printf("pack: %s;
", 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] = '';
 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] = '';
15                 //    printf("pack: %s;
", 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, "
");                
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] = '';
36                         printf("pack: %s;
", 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, "
");
48                 //    //pbrk = strpbrk(pack_buffer, "
");
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] = '';
55                 //        printf("pack: %s;
", 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] = '';
 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] = '';
15                 //    printf("pack: %s;
", 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, "
");                
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] = '';
36                 //        printf("pack: %s;
", 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, "
");
48                     //pbrk = strpbrk(pack_buffer, "
");
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] = '';
55                         printf("pack: %s;
", 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粘包拆包常规处理;
原文地址:https://www.cnblogs.com/linxmouse/p/11590559.html