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 ...
随机推荐
- Ts环境搭建
一.ts环境搭建 安装node.js,用dos命令npm全局安装typescripe包环境 进入vscode官网下载zip文件解压后使用code.exe
- linux中的正则表达式知识梳理
1. 正则表达式 1.1 正则表达式使用 正则表达式是开发者为了处理大量的字符串和文本而定义的一套规则和方法,使用正则表达式可以提高效率,快速获取想要的内容. 正则表达式常用于linux三剑客grep ...
- centos输入正确密码后依旧无法登陆问题
输入正确用户名和密码时依旧无法登录. 进入单用户模式重置密码: 开机启动时,按‘E’键(倒计时结束前)进入界面 选择第二项,按‘E’键再次进入 在最后一行添加‘ 1’(空格 1) 回车键保存,回到该界 ...
- webpack nodejs npm关系
nodejs是js后端运行平台,可以把它看成java体系中对应的jdk,是三个里面最基础的.npm是nodejs的包管理工具,可以把它看成maven中包依赖管理那部分.webpack是前端工程化打包工 ...
- thinkphp v5.1.36 LTS 如果设置跨域访问
修改route/route.php中的路由例如 Route::get('new/:id', 'News/read') ->ext('html') ->header('Access-Cont ...
- App工程结构
在经过千辛万苦各种填坑终于安装好了Android Studio之后,在其自带的模拟器上成功运行了第一个APP(hello world),通过这个APP首先研究了一下APP基本的工程结构,从而使后面的开 ...
- 【Android开发艺术探索】四大组件的工作过程
个人博客 http://www.milovetingting.cn 四大组件的工作过程 四大组件:Activity.Service.BroadcastReceiver.ContentProvider ...
- MySQL锁与事务隔离级别
一.概述 1.锁的定义 锁是计算机协调多个进程或线程并发访问某一资源的机制. 在数据库中,除了传统的计算资源(如CPU.RAM.IO等)的争用以外,数据也是一种供需要用户共享的资源.如何保证数据并发访 ...
- 教你一种简单方法给word和PDF格式的文件使用电子签名
前言 虽然还处在非常时期,但很多公司已陆陆续续复工或准备复工. 上周,人事妹纸给了我们一份,企业员工健康情况申报表.具体如下 现在问题来了,需要本人签名,电脑打上去的不算,需要手写. 此时, ...
- Openshift V3系列各组件版本
Openshift V3.* 系列各组件版本 Components 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.9 3.10 3.11 Core Components dock ...