当前位置: 首页 > news >正文

粘包拆包服务器

服务器:

创建个控制台应用

创建Server.cs

       internal class 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("-------------------------------");//进行拆包1 按照特殊符号进行分割,然后遍历,//对应发数据的代码  buffer = Encoding.UTF8.GetBytes("张三你真牛逼了#");//for (int i = 0; i < s.Split('#').Length-1; i++)//{//    Console.WriteLine("接收到消息为:" + s.Split('#')[i]);//    Send(s.Split('#')[i]);//}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.cs

 internal class 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));}}

战报拆包开客户端:

窗体使用Button方法

 private void button1_Click(object sender, EventArgs e){TcpClient  client = new TcpClient();client.Connect("192.168.107.83", 8080);NetworkStream stream = client.GetStream();//发消息// 第一种方式发消息的时候 每一条消息的结束时候以特殊符合作为结束标志 例如#、\n等符号// 其他端拿到数据之后 对数据进行特殊符号的分割, //byte[] buffer = Encoding.UTF8.GetBytes("我是如来佛祖玉皇大帝观音菩萨指定取西经特派使者花果山水帘洞美猴王齐天大圣孙悟空啊!帅到掉渣!!#");//stream.Write(buffer,0,buffer.Length);//buffer = Encoding.UTF8.GetBytes("张三你真牛逼了#");//stream.Write(buffer, 0, buffer.Length);//buffer = Encoding.UTF8.GetBytes("李四你真牛逼了#");//stream.Write(buffer, 0, buffer.Length);//buffer = Encoding.UTF8.GetBytes("王五你真牛逼了#");//stream.Write(buffer, 0, buffer.Length);//buffer = Encoding.UTF8.GetBytes("马六你真牛逼了#");//stream.Write(buffer, 0, buffer.Length);//调用send方法Send(stream, "世界");Send(stream, "你好埃及文物已到达中国上海");Send(stream, "1111");Send(stream, "222222222");}//第二种发送数据时候 出现粘包现象,后台处粘包//包头当中添加数据长度解决粘包//Send(stream,"123")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();

相关文章:

  • openssl 命令行生成密钥对,生成hash,PSS填充签名,校验
  • x64汇编fastcall调用约定
  • 高阶图神经网络 (HOGNN) 的概念、分类和比较
  • 每月 GitHub 探索|10 款引领科技趋势的开源项目
  • 数学-奇异值
  • STM32通过SPI硬件读写W25Q64
  • MFC GDI绘制卡通人物
  • 长亭网络通信基础
  • LabVIEW、Matlab与Python的比较:从多角度详解三大编程工具
  • 网络安全:Web 安全 面试题.(文件上传漏洞)
  • WPF——属性
  • 案例分享:同为科技与军工项目合作
  • 多层感知器的进化:从基础到并行门控——深入探讨MLP变体的实现、优化与风险
  • 深度解析SD-WAN在企业组网中的应用场景
  • [18] Opencv_CUDA应用之 基于颜色的对象检测与跟踪
  • JS 中的深拷贝与浅拷贝
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • JavaScript 基础知识 - 入门篇(一)
  • Javascript设计模式学习之Observer(观察者)模式
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • 工程优化暨babel升级小记
  • 工作手记之html2canvas使用概述
  • 缓存与缓冲
  • 前端性能优化——回流与重绘
  • 小而合理的前端理论:rscss和rsjs
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • # 利刃出鞘_Tomcat 核心原理解析(二)
  • #android不同版本废弃api,新api。
  • #git 撤消对文件的更改
  • #includecmath
  • $jQuery 重写Alert样式方法
  • (二)windows配置JDK环境
  • (二开)Flink 修改源码拓展 SQL 语法
  • (二十三)Flask之高频面试点
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (三)Kafka 监控之 Streams 监控(Streams Monitoring)和其他
  • (原创)可支持最大高度的NestedScrollView
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • .config、Kconfig、***_defconfig之间的关系和工作原理
  • .NET C# 操作Neo4j图数据库
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET面试题(二)
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • @Controller和@RestController的区别?
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • @font-face 用字体画图标
  • @property python知乎_Python3基础之:property
  • @serverendpoint注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [\u4e00-\u9fa5] //匹配中文字符
  • []sim300 GPRS数据收发程序