1.演示环境为windows 10 1903

2.演示代码

 #include "pch.h"
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h> #pragma comment(lib, "ws2_32.lib") #define BUFFER_LENGTH 256
#define PACK_LENGTH 11
#define PACK_BUFFER_LENGTH 512 int main()
{
char pack_buffer[PACK_BUFFER_LENGTH] = { };
int pack_buffer_len = ; WORD sv = MAKEWORD(, );
WSAData data;
SOCKET client = INVALID_SOCKET; sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
//addr.sin_addr.S_un.S_addr = InetPtonA(AF_INET, "127.0.0.1", NULL);
addr.sin_port = htons(); while (true)
{
while (true)
{
if (WSAStartup(sv, &data) == )
{
client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client != INVALID_SOCKET)
{
if (connect(client, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
{
printf("connect error. reconnecting...\n");
closesocket(client);
WSACleanup();
Sleep();
}
else {
const char *data = "message from client.\n";
int ret = send(client, data, strlen(data), );
//int ret = send(client, "hello world.\n", strlen("hello world.\n"), 0);
printf("socket connected.\n");
break;
}
}
else {
printf("invalid socket.\n");
}
}
} char buffer[];
while (true)
{
int ret = recv(client, buffer, BUFFER_LENGTH, );
if (ret > )
{
// 粘包情况
buffer[ret] = '\0';
printf(buffer); // 1.数据包定长
//char pack[PACK_LENGTH] = { 0 };
//strncat(pack_buffer, buffer, ret);
//pack_buffer_len += ret;
//while (pack_buffer_len >= PACK_LENGTH)
//{
// strncpy(pack, pack_buffer, PACK_LENGTH);
// char spack[PACK_LENGTH + 1] = { 0 };
// strncpy(spack, pack, PACK_LENGTH);
// spack[PACK_LENGTH] = '\0';
// printf("pack: %s;\r\n", spack); // pack_buffer_len -= PACK_LENGTH;
// strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
//} // 2.消息头+消息体 消息头=消息头标识+长度
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// // 去掉消息头+错误包数据
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// len = pack_buffer[0];
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer + 1, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
// }
//} while (pbrk); // 3.特殊字符作为消息结尾
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strstr(pack_buffer, "\r\n");
// //pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// }
//} while (pbrk);
}
else if (ret == )
{
printf("Connection closed\n");
closesocket(client);
WSACleanup();
break;
}
else
{
printf("recv failed: %d\n", WSAGetLastError());
closesocket(client);
WSACleanup();
break;
}
}
} closesocket(client);
WSACleanup(); return ;
}

3.不作拆包处理的情况

 // 粘包情况
buffer[ret] = '\0';
printf(buffer); // 1.数据包定长
//char pack[PACK_LENGTH] = { 0 };
//strncat(pack_buffer, buffer, ret);
//pack_buffer_len += ret;
//while (pack_buffer_len >= PACK_LENGTH)
//{
// strncpy(pack, pack_buffer, PACK_LENGTH);
// char spack[PACK_LENGTH + 1] = { 0 };
// strncpy(spack, pack, PACK_LENGTH);
// spack[PACK_LENGTH] = '\0';
// printf("pack: %s;\r\n", spack); // pack_buffer_len -= PACK_LENGTH;
// strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
//} // 2.消息头+消息体 消息头=消息头标识+长度
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// // 去掉消息头+错误包数据
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// len = pack_buffer[0];
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer + 1, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
// }
//} while (pbrk); // 3.特殊字符作为消息结尾
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strstr(pack_buffer, "\r\n");
// //pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// }
//} while (pbrk);

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

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

socket connected.
123456abc123456abc123456abc123456abc123456abc123456abc123456abc123456abc123456abc123456abc

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

 // 粘包情况
//buffer[ret] = '\0';
//printf(buffer); // 1.数据包定长
char pack[PACK_LENGTH] = { };
strncat(pack_buffer, buffer, ret);
pack_buffer_len += ret;
while (pack_buffer_len >= PACK_LENGTH)
{
strncpy(pack, pack_buffer, PACK_LENGTH);
char spack[PACK_LENGTH + ] = { };
strncpy(spack, pack, PACK_LENGTH);
spack[PACK_LENGTH] = '\0';
printf("pack: %s;\r\n", spack); pack_buffer_len -= PACK_LENGTH;
strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
} // 2.消息头+消息体 消息头=消息头标识+长度
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// // 去掉消息头+错误包数据
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// len = pack_buffer[0];
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer + 1, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
// }
//} while (pbrk); // 3.特殊字符作为消息结尾
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strstr(pack_buffer, "\r\n");
// //pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// }
//} while (pbrk);

使用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.使用消息头+消息体 消息头=消息头标识+长度

 // 粘包情况
//buffer[ret] = '\0';
//printf(buffer); // 1.数据包定长
//char pack[PACK_LENGTH] = { 0 };
//strncat(pack_buffer, buffer, ret);
//pack_buffer_len += ret;
//while (pack_buffer_len >= PACK_LENGTH)
//{
// strncpy(pack, pack_buffer, PACK_LENGTH);
// char spack[PACK_LENGTH + 1] = { 0 };
// strncpy(spack, pack, PACK_LENGTH);
// spack[PACK_LENGTH] = '\0';
// printf("pack: %s;\r\n", spack); // pack_buffer_len -= PACK_LENGTH;
// strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
//} // 2.消息头+消息体 消息头=消息头标识+长度
strncat(pack_buffer, buffer, ret);
char *pbrk = NULL;
do
{
pbrk = strpbrk(pack_buffer, "\r\n");
if (pbrk != NULL)
{
int len = pbrk - pack_buffer;
// 去掉消息头+错误包数据
strncpy(pack_buffer, pack_buffer + len + , PACK_BUFFER_LENGTH - (len + ));
len = pack_buffer[];
char *pack = (char *)malloc(len + );
strncpy(pack, pack_buffer + , len);
pack[len] = '\0';
printf("pack: %s;\n", pack);
free(pack);
strncpy(pack_buffer, pack_buffer + len + , PACK_BUFFER_LENGTH - (len + ));
}
} while (pbrk); // 3.特殊字符作为消息结尾
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strstr(pack_buffer, "\r\n");
// //pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// }
//} while (pbrk);

使用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.特殊字符作为消息结尾

 // 粘包情况
//buffer[ret] = '\0';
//printf(buffer); // 1.数据包定长
//char pack[PACK_LENGTH] = { 0 };
//strncat(pack_buffer, buffer, ret);
//pack_buffer_len += ret;
//while (pack_buffer_len >= PACK_LENGTH)
//{
// strncpy(pack, pack_buffer, PACK_LENGTH);
// char spack[PACK_LENGTH + 1] = { 0 };
// strncpy(spack, pack, PACK_LENGTH);
// spack[PACK_LENGTH] = '\0';
// printf("pack: %s;\r\n", spack); // pack_buffer_len -= PACK_LENGTH;
// strncpy(pack_buffer, pack_buffer + PACK_LENGTH, PACK_BUFFER_LENGTH - PACK_LENGTH);
//} // 2.消息头+消息体 消息头=消息头标识+长度
//strncat(pack_buffer, buffer, ret);
//char *pbrk = NULL;
//do
//{
// pbrk = strpbrk(pack_buffer, "\r\n");
// if (pbrk != NULL)
// {
// int len = pbrk - pack_buffer;
// // 去掉消息头+错误包数据
// strncpy(pack_buffer, pack_buffer + len + 2, PACK_BUFFER_LENGTH - (len + 2));
// len = pack_buffer[0];
// char *pack = (char *)malloc(len + 1);
// strncpy(pack, pack_buffer + 1, len);
// pack[len] = '\0';
// printf("pack: %s;\n", pack);
// free(pack);
// strncpy(pack_buffer, pack_buffer + len + 1, PACK_BUFFER_LENGTH - (len + 1));
// }
//} while (pbrk); // 3.特殊字符作为消息结尾
strncat(pack_buffer, buffer, ret);
char *pbrk = NULL;
do
{
pbrk = strstr(pack_buffer, "\r\n");
//pbrk = strpbrk(pack_buffer, "\r\n");
if (pbrk != NULL)
{
int len = pbrk - pack_buffer;
char *pack = (char *)malloc(len + );
strncpy(pack, pack_buffer, len);
pack[len] = '\0';
printf("pack: %s;\n", pack);
free(pack);
strncpy(pack_buffer, pack_buffer + len + , PACK_BUFFER_LENGTH - (len + ));
}
} while (pbrk);

使用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常用拆包处理的更多相关文章

  1. 开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等

    开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等 C++开发网络通信程序时用asio是个不错的选择 ...

  2. TCP常用网络和木马使用端口对照表,常用和不常用端口一览表

    [开始-运行- CMD , 输入 netstat -an 然后回车就可以查看端口] 端口: 服务:Reserved 说明:通常用于分析操作系统.这一方法能够工作是因为在一些系统中“”是无效端口,当你试 ...

  3. netty解决TCP的拆包和粘包的解决办法

    TCP粘包.拆包问题 熟悉tcp编程的可能知道,无论是服务端还是客户端,当我们读取或者发送数据的时候,都需要考虑TCP底层的粘包个拆包机制. tcp是一个“流”协议,所谓流就是没有界限的传输数据,在业 ...

  4. TCP 常用总结

    SO_RCVBUF SO_SNDBUF TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,不管进程是否读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲 ...

  5. nagios系列(四)之nagios主动方式监控tcp常用的80/3306等端口监控web/syncd/mysql及url服务

    nagios主动方式监控tcp服务web/syncd/mysql及url cd /usr/local/nagios/libexec/ [root@node4 libexec]# ./check_tcp ...

  6. TCP 粘包/拆包问题

    简介    TCP 是一个’流’协议,所谓流,就是没有界限的一串数据. 大家可以想想河里的流水,是连成一片的.期间并没有分界线, TCP 底层并不了解上层业务数据的具体含义 ,它会根据 TCP 缓冲区 ...

  7. 关于TCP的粘包和拆包

    问题产生 一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这个就是TCP的拆包和封包问题. 下面可以看一张图,是客户端向服务端发送包: 1. 第一种情况 ...

  8. TCP粘包和拆包问题

    问题产生 一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这个就是TCP的拆包和封包问题. 下面可以看一张图,是客户端向服务端发送包: 1. 第一种情况 ...

  9. 常用的TCP Option

    当前,TCP常用的Option如下所示———— Kind (Type) Length Name Reference 描述 & 用途 0 1 EOL RFC 793 选项列表结束 1 1 NOP ...

随机推荐

  1. 关键两步+6个要点,让Windows应用程序享有K8S的绝佳优势

    本文来自Rancher Labs 前  言 实际上,没有一个迁移路径能够适用于将所有传统应用程序迁移到云.这些应用程序通常在物理机.虚拟机或本地.虽然一般情况下是重新设计应用程序架构以适用云原生服务, ...

  2. python新手如何编写一个猜数字小游戏

    此文章只针对新手,希望大家勿喷,感谢!话不多说先上代码: import random if __name__ == '__main__': yourname = input("你好! 你的名 ...

  3. 9种分布式ID生成之 美团(Leaf)实战

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...

  4. linux的分区和文件系统

    一.分区类型 主分区 总共最多能分四个 扩展分区 只能有一个,也算做主分区的一种,也就是说主分区加扩展分区最多有4个. 但是扩展分区不能存储数据和格式化,必须在划分成逻辑分区才能使用. 逻辑分区 逻辑 ...

  5. C++ Primer抄书笔记(二)——变量和基本类型(下)

    四.const限定符[引用/指针/顶层/常量表达式] const对象值不变,必须初始化,能完成此type的大部分operation. 一般,多文件独立变量,编译初始化仅文件内有效: 除非,(条件:初值 ...

  6. Java之GUI编程

    GUI编程 组建 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事件 破解工具 1.简介 GUI的核心技术:Swing AWT 为什么不流行? 界面不美观. 需要jre环境.(没必 ...

  7. oracle 数据库 Cause: java.sql.SQLSyntaxErrorException: ORA-00904: "BODY": 标识符无效

    1.全大写或者加引号 SELECT TEST_NAME FROM T_TEST  或者 SELECT “test_name” from "t_user"

  8. 树莓派搭载CentOS7系统初始配置

    系统属性: 树莓派型号:3b SD:32GB 系统:CentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1908-sda.raw 开机配置: 连接树莓派: 配件 ...

  9. 迅雷X v10.1.29.698-免安装SVIP去广告精简版+骨头版+便携版+手雷+Mac精简版

    迅雷X 10.1版本开始,采用Electron软件框架完全重写了迅雷主界面.使用新框架的迅雷X可以完美支持2K.4K等高清显示屏,界面中的文字渲染也更加清晰锐利.新框架的界面绘制.事件处理等方面比老框 ...

  10. windows2016_x64搭建ELK(datasource->filebeat->logstash->elasticsearch->kibana)

    windows2016_x64搭建ELK(datasource->filebeat->logstash->elasticsearch->kibana) 本文示例日志程序基于as ...