TCP常用拆包处理
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常用拆包处理的更多相关文章
- 开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等
开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等 C++开发网络通信程序时用asio是个不错的选择 ...
- TCP常用网络和木马使用端口对照表,常用和不常用端口一览表
[开始-运行- CMD , 输入 netstat -an 然后回车就可以查看端口] 端口: 服务:Reserved 说明:通常用于分析操作系统.这一方法能够工作是因为在一些系统中“”是无效端口,当你试 ...
- netty解决TCP的拆包和粘包的解决办法
TCP粘包.拆包问题 熟悉tcp编程的可能知道,无论是服务端还是客户端,当我们读取或者发送数据的时候,都需要考虑TCP底层的粘包个拆包机制. tcp是一个“流”协议,所谓流就是没有界限的传输数据,在业 ...
- TCP 常用总结
SO_RCVBUF SO_SNDBUF TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,不管进程是否读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲 ...
- 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 ...
- TCP 粘包/拆包问题
简介 TCP 是一个’流’协议,所谓流,就是没有界限的一串数据. 大家可以想想河里的流水,是连成一片的.期间并没有分界线, TCP 底层并不了解上层业务数据的具体含义 ,它会根据 TCP 缓冲区 ...
- 关于TCP的粘包和拆包
问题产生 一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这个就是TCP的拆包和封包问题. 下面可以看一张图,是客户端向服务端发送包: 1. 第一种情况 ...
- TCP粘包和拆包问题
问题产生 一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这个就是TCP的拆包和封包问题. 下面可以看一张图,是客户端向服务端发送包: 1. 第一种情况 ...
- 常用的TCP Option
当前,TCP常用的Option如下所示———— Kind (Type) Length Name Reference 描述 & 用途 0 1 EOL RFC 793 选项列表结束 1 1 NOP ...
随机推荐
- zabbix 自定义监控项每隔1分钟检测一次三次失败报警
在agent上添加 UserParameter=auth.check,/etc/zabbix/auth_monitor/auth_check.py auth.check就是之后添加的自定义的item值 ...
- Qt Python Scriptable Application
Qt Python Scriptable Application eryar@163.com Abstract. Python and C++ are in many ways as differen ...
- Nginx之常用基本配置
上一篇博客我们大概介绍了一下nginx,nginx的架构,nginx编译安装和nginx命令的用法,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/1236680 ...
- Cesium案例解析(六)——3DTilesInspector监视器
目录 1. 概述 2. 案例 1. 概述 3D Tiles作为传输和渲染大规模3D地理空间数据的格式,应对的都是大规模数据的场景,Cesium提供了一个监视3D Tiles数据的监视器,可以通过这个监 ...
- opencv —— inpaint 图像修补、去除指定区域物体
实现图像修补.物体去除:inpaint 函数 void inpaint(InputArray src, InputArray inpaintMask, OutputArray dst, double ...
- PLSQL-Initialization error
1. 情况描述 安装完PLSQL之后,在写入数据库连接信息后,连接数据库,报Initialization error错误 (1)未安装Oracle数据库,无相应的oci.dll文件 (2)已安装数据库 ...
- " ModuleNotFoundError: No module named 'tkinter' "的解决方法
踩坑场景 在使用pillow这个包处理图片的时候,运行程序,报错ModuleNotFoundError: No module named 'tkinter',遇到ModuleNotFoundError ...
- Node.js核心模块-fs文件系统
fs是file-system的简写,文件系统的意思.在Node中如果想要进行文件操作,就必须引入fs这个核心模块. 引入 const fs = require('fs') fs.readFile(pa ...
- postman请求(请求方式、请求url、请求参数、参数类型、请求头)
请求方式:get 请求地址: 请求参数:url与参数用?间隔,多个参数用&间隔 请求方式:post 请求地址: 请求参数: 请求参数格式:前面两种是key-value.第三种可以选择json/ ...
- PyCharm2019 永久激活(测试通过)
2019.1.1 专业版 永久期限,需要下载补丁,以及配置文件 补丁地址:https://pan.baidu.com/s/16ALpz_BCXjsRkpS_PtD23A 1,下载安装pycharm程序 ...