通信网络
如何用最简单的方法解决TCP传输中的分包粘包问题?
首先需要说明一点,分包粘包等等一系列的问题并不是协议本身存在的问题,而是程序员在写代码的时候,没有搞清楚数据的边界导致的。 看个简单的例子,TCP客户端不断的向服务器发送字符串,每次发送完成随机睡眠一会。
char *buf[] = { "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbb", "ccccccccccccccccccc", "dddddddddddddddddddddddddddddddddddddddddddd", "eeeeeeeeeeeeeeeeeeeeeeee", "ffffffff", "gggggggggggggggggggggggggggggggggggg", "hhhhhhhhhhhhhhhhhhhhhhhhhhhhh", "iii", "jjjjjjj", "kkkkkkkkkkkkkkkkkkkkkk" }; srand(time(NULL)); for (int i = 0; i < sizeof(buf) / sizeof(buf[0]); i++) { if (send(sockfd, buf[i], strlen(buf[i]), 0) == -1) { perror("send"); break; } usleep(1000 * 10); }服务器端接收数据的时候同样如此。
char buf[1024] = {0}; srand(time(NULL)); while (1) { size = recv(fd, buf, sizeof(buf), 0); if (size == -1) { perror("recv"); break; } else if (size == 0) { printf("客户端断开连接 ... "); break; } printf("收到一条数据 %s ", buf); bzero(buf, 1024); usleep(1000 * (rand() % 100 + 1)); }我们希望看到的现象是,服务器端收到的数据和客户端一样。 运行程序,客户端发送完成,但是服务器端收到的数据却不是我们想要的。
root@Turbo:test# ./1.tcp-server 等待客户端的连接 ... 接受客户端的连接 4 收到一条数据 aaaaaaaaaaaaaaaaaaaaaaaaaaaa 收到一条数据 bbbbbbbbbbbcccccccccccccccccccddddddddddddddddddddddddddddddddddd dddddddddeeeeeeeeeeeeeeeeeeeeeeeeffffffffgggggggggggggggggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiijjjjjjj收到一条数据 kkkkkkkkkkkkkkkkkkkkkk 客户端断开连接 ... root@Turbo:test#数据内容没有变,出现了多个字符串连接在一起的现象。 原因就是发送数据过快,或者接收数据太慢,导致TCP缓冲区中积累了很多数据,调用recv函数读数据的时候,就会一下子全部读出来。 想要解决这个问题,最简单的办法就是分清楚数据包的边界。发送字符串之前,在数据包的前面加上字符串的长度。
char *sendMsg = (char *)malloc(1024); int len = 0; srand(time(NULL)); for (int i = 0; i < sizeof(buf) / sizeof(buf[0]); i++) { len = strlen(buf[i]); memcpy(sendMsg, &len, sizeof(int)); memcpy(sendMsg + sizeof(int), buf[i], len); if (send(sockfd, sendMsg, strlen(buf[i]) + sizeof(int), 0) == -1) { perror("send"); break; } memset(sendMsg, 0, 1024); usleep(1000 * 10); }接收数据的时候,先读取4个字节的整型数据,得到接下来字符串的长度,再读取对应长度的字符串。
char buf[1024] = {0}; ssize_t size; int len = 0; srand(time(NULL)); while (1) { size = recv(fd, &len, sizeof(int), 0); size = recv(fd, buf, len, 0); if (size == -1) { perror("recv"); break; } else if (size == 0) { printf("客户端断开连接 ... "); break; } printf("收到一条数据 %s ", buf); bzero(buf, 1024); usleep(1000 * (rand() % 100 + 1)); }再次运行程序,不管睡眠时间怎么变化,服务器端收到的数据和客户端一样,也没有出现粘在一起的现象。
root@Turbo:test# ./1.tcp-server 等待客户端的连接 ... 接受客户端的连接 4 收到一条数据 aaaaaaaaaaaaaaaaaaaaaaaaaaaa 收到一条数据 bbbbbbbbbbb 收到一条数据 ccccccccccccccccccc 收到一条数据 dddddddddddddddddddddddddddddddddddddddddddd 收到一条数据 eeeeeeeeeeeeeeeeeeeeeeee 收到一条数据 ffffffff 收到一条数据 gggggggggggggggggggggggggggggggggggg 收到一条数据 hhhhhhhhhhhhhhhhhhhhhhhhhhhhh 收到一条数据 iii 收到一条数据 jjjjjjj 收到一条数据 kkkkkkkkkkkkkkkkkkkkkk方法很简单,也只是加了一个包头,其实目的就是为了告诉接收端,数据包从哪开始,到哪结束,这样就算缓冲区中有大量数据,也能分得清楚。
编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !