tcp 粘包和拆包 及 解决粘包方案

什么是粘包和拆包

.TCP 是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的 socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(Nagle 算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样做虽然提高了效率,但是接收端就难于分辨出完整的数据包了,因为面向流的通信是无消息保护边界的

粘包和拆包是网络编程中常遇到的问题,主要是因为TCP协议的Nagle算法和接收方缓冲区的不足导致的。
粘包:发送方发送的若干包数据到接收方接收时粘在一起,导致数据不能正确分割。
拆包:发送方发送的包数据在接收方解析时被拆开,导致数据不能正确解析。


客户端

直接发消息

第一种方式发消息的时候 每一条消息的结束时候以特殊符合作为结束标志 例如#、\n等符号
            // 其他端拿到数据之后 对数据进行特殊符号的分割

TcpClient  client = new TcpClient();
client.Connect("端口号", 8080);
NetworkStream stream = client.GetStream();
Send(stream, "三十而立,指的是拥有了30个重装合成旅,才能在这个星球上拥有立足的资本");
Send(stream, "四十而不惑,指的是拥有40个重装合成旅,这个星球上就没有能让我们感到困惑的事");
Send(stream, "五十而知天命,指的是拥有50个重装合成旅,这个星球的其他国家便能知道我们所说的话便是他的天命");

第二种发送数据时候 出现粘包现象,后台处粘包
        //包头当中添加数据长度解决粘包

void Send(NetworkStream stream,string msg)
{//1定义一个字节数组获取发送数据字节流byte[] bs = Encoding.UTF8.GetBytes(msg);//2 创建一个内存流,存在内存当中,可以理解为虚拟的文件流MemoryStream ms = new MemoryStream();//3 创建一个二进制读写对象 写入内存流BinaryWriter bw = new BinaryWriter(ms);//4写入数据的长度的bw.Write(bs.Length);//5 写入数据字节数组bw.Write(bs);//6 发送数据 把数据长度和数据内容同时发给服务器stream.Write(ms.ToArray(), 0, ms.ToArray().Length);bw.Close();ms.Close();}

服务器:

Server封装:
TcpListener listen;
public Server(IPAddress ip,int port) 
{listen = new TcpListener(ip, port);
}public void Start()
{listen.Start(100);StartConnect();  
}
Dictionary<string,TcpClient> clientDic = new Dictionary<string,TcpClient>();
public event Action<TcpClient> 有客户端连入的事件; 
void StartConnect()
{Task.Run(() =>{while (true) {TcpClient client = listen.AcceptTcpClient();string ip = client.Client.RemoteEndPoint.ToString(); clientDic.Add(ip, client);有客户端连入的事件?.Invoke(client);startRead(client);//读取粘包的数据,在这个方法进行拆包处理}});
}

拆包

public void startRead(TcpClient t1)
{//接受客户端发来的数据NetworkStream stream = t1.GetStream();string ip = t1.Client.RemoteEndPoint.ToString();byte[] bs = new byte[1024 * 1024];Task.Run(() =>{try{while (true){int count=  stream.Read(bs, 0, bs.Length);if (count== 0){throw new Exception("客户端断了");}//接受数据byte[] body = bs.Take(count).ToArray();string s = Encoding.UTF8.GetString(body);Console.WriteLine("-------------------------------");Console.WriteLine("接收到消息为:"+s);Console.WriteLine("-------------------------------");if (上一个数据半包 != null) //判断是否有半包 如果有,把半包取出来和当前包合并{body =  上一个数据半包.Concat(body).ToArray();//把俩个数组合成一个数组上一个数据半包 = null; //清空半包}//开始拆包 封装一个拆包方法//参数1  当前要拆的数据//参数2 第几个位置开始拆//参数3 当前客户端ChaiBao(body, 0, t1);}}catch (Exception ex){clientDic.Remove(ip);}});
}
 byte[] 上一个数据半包 = null;public void ChaiBao(byte[] bytes ,int startIndex, TcpClient client){if(startIndex+4>bytes.Length) {//如果开始位置加上4大于该数据包的长度时候 说明当前包是一个半包//跳过之前元素,取出剩余的数据上一个数据半包 = bytes.Skip(startIndex).ToArray();return;}//计算第一个包长度 获取从开始到startIndex之间的长度int len = BitConverter.ToInt32 (bytes,startIndex);// 取出对应位置包的总体大小// 之前的包长度总和int abc = len + startIndex + 4;//判断当前包是整包还是半包或者是多包if (abc == bytes.Length) { //如果之前所有包的大小加上当前数据包大小等于全包的长度,证明当前是一个整包byte[] bs1  = bytes.Skip(startIndex+4).ToArray();接受到消息的事件?.Invoke(client, bs1);}else if (abc < bytes.Length){byte[] bs2 =   bytes.Skip(startIndex+4).Take(len).ToArray();接受到消息的事件?.Invoke(client, bs2);//如果之前包加上当前包小于全包的长度,说明当前包是多包。如果是多包,再进行拆包ChaiBao(bytes, abc, client);}else{ //目前是一个半包上一个数据半包 = bytes.Skip (startIndex).ToArray();}}
群发方法
 public event Action<string> 客户端断开事件; public event Action<TcpClient, byte[]> 接受到消息的事件;public Server(){}//群发方法 向所有的客户端发消息public void Send(string content){byte[] bs = Encoding.UTF8.GetBytes(content);foreach (var item in clientDic) //遍历所有的客户端{item.Value.GetStream().Write(bs, 0, bs.Length);}}//指定给谁发public void Send(string content,string ip) {byte[] bs = Encoding.UTF8.GetBytes(content);//根据ip取出客户端,从字典取clientDic[ip].GetStream().Write(bs, 0, bs.Length);}//指定给哪些客户端发//send("你好", ["192.","127"])public void Send(string content, string[] ips){byte[] bs = Encoding.UTF8.GetBytes(content);foreach (var item in clientDic) //所有客户端{//item.key 键 ip字符串//item.value 值 客户端对象if (ips.Contains(item.Key)){//如果ips数组包含目标客户端item.Value.GetStream().Write(bs, 0, bs.Length);}}}
Program
static Server s;static void Main(string[] args){s = new Server(IPAddress.Any,8080);s.有客户端连入的事件 += f1;s.接受到消息的事件 += f2;s.Start();Console.ReadKey();}public static void f1(TcpClient t1){Console.WriteLine(t1.Client.RemoteEndPoint.ToString()+"连接到服务器");}public static void f2(TcpClient t2, byte[] bs){Console.WriteLine(t2.Client.RemoteEndPoint.ToString()+"发来的消息为+++++++++++:"+ Encoding.UTF8.GetString(bs,0,bs.Length));}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/31078.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CIRCOS圈图绘制 - circos安装

Circos是绘制圈图的神器&#xff0c;在http://circos.ca/images/页面有很多CIRCOS可视化的示例。 Circos可以在线使用&#xff0c;在线使用时是把表格转为圈图&#xff0c;不过只允许最大75行和75列&#xff1b;做一些简单的示意图会比较好&#xff0c;最后时会介绍下在线的tab…

anaconda-pip源

在Anaconda环境中&#xff0c;使用pip安装Python包时&#xff0c;默认的PyPI源可能会因网络问题导致下载速度慢或无法连接。为了解决这个问题&#xff0c;可以将pip的默认源更换为国内的镜像源。以下是在Anaconda中如何进行pip换源的详细步骤&#xff1a; 1. 打开Anaconda Pro…

第二十四篇——纠错码:对待错误的正确态度是什么?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 当我们面对错误的发生&#xff0c;是一个确定事件的时候&#xff1b;我们…

十大机器学习算法深入浅出

本栏目涉及对于回归算法、聚类算法、决策树、随机森林、神经网络、贝叶斯算法、支持向量机等十大机器学习算法的笔记 下面是笔记大纲&#xff0c;具体内容可查看**“十大机器学习算法深入浅出”**专栏&#xff0c;内容持续更新&#xff0c;欢迎订阅专栏和专注我&#xff01; 1…

Golang | Leetcode Golang题解之第169题多数元素

题目&#xff1a; 题解&#xff1a; func majorityElement(nums []int) (ans int) {cnts : 0for _, v : range nums {if v ans {cnts} else if cnts 0 {ans v} else {cnts--}}return }

python flask配置邮箱发送功能,使用flask_mail模块

&#x1f308;所属专栏&#xff1a;【Flask】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点…

使用Python和BeautifulSoup轻松抓取表格数据

你是否曾经希望可以轻松地从网页上获取表格数据&#xff0c;而不是手动复制粘贴&#xff1f;好消息来了&#xff0c;使用Python和BeautifulSoup&#xff0c;你可以轻松实现这一目标。今天&#xff0c;我们将探索如何使用这些工具抓取中国气象局网站(http://weather.cma.cn)上的…

Spring Boot集成tensorflow实现图片检测服务

1.什么是tensorflow&#xff1f; TensorFlow名字的由来就是张量(Tensor)在计算图(Computational Graph)里的流动(Flow)&#xff0c;如图。它的基础就是前面介绍的基于计算图的自动微分&#xff0c;除了自动帮你求梯度之外&#xff0c;它也提供了各种常见的操作(op&#xff0c;…

蓝桥杯 经典算法题 Fizz Buzz 经典问题

题目&#xff1a; 给定一个整数 N&#xff0c;从 1 到 N 按照下面的规则返回每个数&#xff1a; 如果这个数被 3 整除&#xff0c;返回 Fizz。如果这个数被 5 整除&#xff0c;返回 Buzz如果这个数能同时被 3 和 5 整除&#xff0c;返回 FizzBuzz。如果这个数既不能被 3 也不…

python爬虫之selenium自动化操作

python爬虫之selenium自动化操作 需求&#xff1a;操作淘宝去掉弹窗广告搜索物品后进入百度回退又前进 selenium模块的基本使用 问题&#xff1a;selenium模块和爬虫之间具有怎样的关联? 1、便捷的获取网站中动态加载的数据 2、便捷实现模拟登录 什么是selenium模块&#x…

maven-jar-plugin maven打包插件笔记

文章目录 配置示例 其他官网文档问题maven打包插件是如何和打包动作关联在一起的?配置文件中 goal是必须的吗? maven自定义插件内容很多&#xff0c;也不易理解&#xff0c;这里把maven打包插件单拿出来&#xff0c;作为入口试着理解下。 配置示例 <plugin><groupI…

ubuntu22.04禁止自动休眠的几种方式

在Ubuntu 20.04中&#xff0c;您可以通过以下几种方式禁用自动休眠功能&#xff1a; 使用systemd设置: sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target 修改/etc/systemd/logind.conf文件: sudo nano /etc/systemd/logind.conf 找…

番外篇 | 基于YOLOv5-RCS的明火烟雾检测 | 源于RCS-YOLO

前言:Hello大家好,我是小哥谈。RCS-YOLO是一种目标检测算法,它是基于YOLOv3算法的改进版本。通过查看RCS-YOLO的整体架构可知,其中包括RCS-OSA模块。RCS-OSA模块在模型中用于堆叠RCS模块,以确保特征的复用并加强不同层之间的信息流动。本文就给大家详细介绍如何将RCS-YOLO…

<Linux> 基础IO

文章目录 基础IO文件描述符重定向重定向本质重定向系统调用 基础IO 文件描述符 系统底层提供打开文件(open)&#xff0c;读(read)&#xff0c;写(write)&#xff0c;关闭文件(close)的系统调用&#xff0c;如果想详细了解可以复制以下命令仔细阅读使用方法&#xff0c;这里不…

C++程序编译 错误提示和评测状态

编译常见错误提示 1.[Error] expected ; before cout。在cout前面&#xff0c;缺少一个分号。 2.[Error] arr was not declared in this scope。未定义变量名arr。 3.[Error] ld returned 1 exit status。重复运行错误(上一个运行的程序&#xff0c;输入窗口没有关掉)。 或者…

如何解决windows自动更新,释放C盘更新内存

第一步&#xff1a;首先关闭windows自动更新组件 没有更新windows需求&#xff0c;为了防止windows自动更新&#xff0c;挤占C盘空间&#xff0c;所以我们要采取停止Windows Update服务。按下WinR打开运行对话框&#xff0c;输入services.msc&#xff0c; 然后按Enter。在服务…

24上软考成绩预计6月底公布?附查分指南

最近&#xff0c;很多小伙伴都在问上半年成绩什么时候出来&#xff1f;每天学习群变成了祈祷群&#xff0c;都在祈祷45,45,45。按照上一次的成绩发布时间&#xff0c;从考试结束到成绩发布&#xff0c;间隔了32天。这次是不是会更快&#xff1f; 一般阅卷只要7-10天&#xff0c…

vb.net教程

下载地址&#xff1a;https://download.csdn.net/download/wgxds/89462547

内核模块的各种概念及示例

基本概念 (1)模块本身不被编译入内核映像&#xff0c;从而控制了内核镜像的大小。模块一旦insmod&#xff0c;它就和内核中的其他部分完全一样 (2)内核中已加载模块的信息也存在于/sys/module目录下&#xff1b;内核中将包含/sys/module/test_mod目录 (3)modprobe在加载某模…

系统架构设计师 - 数据库系统(1)

数据库系统 数据库系统数据库模式 ★分布式数据库 ★★★数据库设计阶段 ★★ER模型 ★关系模型 ★ ★结构约束条件完整性约束 关系代数 ★ ★ ★ ★概述自然连接 大家好呀&#xff01;我是小笙&#xff0c;本章我主要分享系统架构设计师 - 数据库系统(1)知识&#xff0c;希望内…