tcp 客户端进行拆包

心跳机制服务器

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("-------------------------------");Send(s);// 群发}}catch (Exception ex){clientDic.Remove(ip);}});}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));}

客户端

TcpClient client;public Form1(){InitializeComponent();client = new TcpClient();client.Connect("192.168.107.60",8080);// 开始接收数据startReceive(client);}void startReceive(TcpClient t1){byte[] bs = new byte[1024]; // 缓存区Task.Run(() =>{try{while (true){int count = t1.GetStream().Read(bs, 0, bs.Length);if(count == 0){Console.WriteLine("服务器断开");break;}// 去掉数据最后一位占位0byte[] data = bs.Take(count).ToArray();// 需不需要拆包Console.WriteLine(Encoding.UTF8.GetString(data));if(lastPack != null){data = lastPack.Concat(data).ToArray();lastPack = null;}ChaiBao(data, 0, t1);}}catch (Exception ex){Console.WriteLine("客户端断开");}});}byte[] lastPack = null;// 上一个半包public void ChaiBao(byte[] bs,int startIndex,TcpClient t1){if (startIndex + 4 > bs.Length){lastPack = bs.Skip(startIndex).ToArray(); // 跳过开始位置取出后面的return;}// 记录第一个包的长度int len = BitConverter.ToInt32(bs, startIndex);// 取出之前所有包的长度int abc = len + startIndex + 4;Console.WriteLine(abc + "?????" + bs.Length);if(abc == bs.Length){byte[] bs1 = bs.Skip(startIndex + 4).ToArray();richTextBox1.Invoke((Action)(() =>{richTextBox1.AppendText(Encoding.UTF8.GetString(bs1) + "\n");}));}else if (abc < bs.Length){byte[] bs2 = bs.Skip(startIndex + 4).Take(len).ToArray();richTextBox1.Invoke((Action)(() =>{richTextBox1.AppendText(Encoding.UTF8.GetString(bs2) + "\n");richTextBox1.SelectionStart = richTextBox1.Text.Length;richTextBox1.ScrollToCaret();}));// 继续拆包ChaiBao(bs, abc, t1);}else{lastPack = bs.Skip(startIndex).ToArray();}}

直接发消息

调用MemoryStream进行添加数据长度的方法

Send(client.GetStream(), "大帅的几种形态");
Send(client.GetStream(), "精致大帅");
Send(client.GetStream(), "油腻大帅");
Send(client.GetStream(), "虚币大帅");
Send(client.GetStream(), "变态大帅");
Send(client.GetStream(), "人妻大帅");

没有使用MemoryStream进行添加数据长度

 Send("罗罗诺亚·索隆");Send("蒙奇·D·路飞");Send("文斯莫克·山治");Send("托尼托尼·乔巴");Send("妮可·罗宾");

MemoeySteream内存流把数据长度和数据内容写在一个包里

void Send(NetworkStream stream, string msg)
{byte[] bs = Encoding.UTF8.GetBytes(msg); // 先转成字符节数组MemoryStream ms = new MemoryStream();// 创建内存流BinaryWriter bw = new BinaryWriter(ms); // 创建内存流bw.Write(bs.Length);// 写入长度bw.Write(bs);// 写入内容stream.Write(ms.ToArray(), 0, ms.ToArray().Length);// 发送内容流bw.Close();// 关闭写入对象ms.Close();// 关闭内存流
}void Send(string msg)
{byte[] bs = Encoding.UTF8.GetBytes(msg); // 把发的消息转成字节数组// BitConverter 转成位数据// 把字节数组长度转成位格式数据byte[] len = BitConverter.GetBytes(bs.Length);byte[] body = len.Concat(bs).ToArray(); // 把数据长度和内容存在一个包里面    client.GetStream().Write(body, 0, body.Length);}

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

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

相关文章

CANoe CAPL如何模拟发送CAN错误帧?

目录 canOutputErrorFrame介绍代码output(errorframe)代码总结canOutputErrorFrame 介绍 代码 canOutputErrorFrame(errorFrame, 12, 0); //output Error Frame with 12 dominant bits on CAN1 canOutputErrorFrame(CAN2.errorFrame, 6,

快手可灵大模型开放视频续写功能,可生成最长约3分钟视频

6月21日&#xff0c;可灵再度进化&#xff0c;正式推出图生视频功能&#xff0c;支持用任意静态图像生成5s视频&#xff0c;并且可搭配不同的文本内容&#xff0c;实现丰富的视觉叙事 。 同时&#xff0c;可灵还发布了业内领先的视频续写功能&#xff0c;可为已生成的视频&…

【乐吾乐2D可视化组态编辑器】弹框

很多同学问道&#xff1a;如何弹框。Meta2d.js只通知弹框&#xff0c;不直接弹框。 原因很简单&#xff0c;我们不知道用户需要什么样的弹框&#xff0c;弹框通常涉及具体业务数据&#xff0c;只有业务自己知道。 External Player - 哔哩哔哩嵌入式外链播放器 乐吾乐2D可视化…

Chromium 开发指南2024 Mac篇-开始编译Chromium(五)

1.引言 在之前的指南中&#xff0c;我们已经详细介绍了在 macOS 上编译和开发 Chromium 的准备工作。您学会了如何安装和配置 Xcode&#xff0c;如何下载和配置 depot_tools&#xff0c;以及如何获取 Chromium 的源代码。通过这些步骤&#xff0c;您的开发环境已经搭建完毕&am…

在没有安装 Qt 的 Linux 上启动 Qt5 应用时出现 “Failed to load platform plugin ‘xcb‘“ 错误的解决方法

在Linux系统上开发和部署Qt5应用时&#xff0c;有时会遇到一个令人头痛的问题——当你在没有安装Qt SDK的系统上运行应用程序时&#xff0c;控制台出现如下错误信息&#xff1a; Failed to load platform plugin "xcb". Available platforms are:原因分析 这个问题…

如何级联移位寄存器(74HC595)

在这个项目中&#xff0c;我们将使用 74HC595 移位寄存器将 2 个移位寄存器级联在一起。这样级联移位寄存器现在可以控制 16 个输出。 当然您可以级联任意数量的移位寄存器。如果您要级联第三个移位寄存器&#xff0c;它可以控制 24 个输出。如果您级联第四个移位寄存器&#x…

任务3.8.4 利用RDD实现分组排行榜

文章目录 1. 任务说明2. 解决思路3. 准备成绩文件4. 采用交互式实现5. 采用Spark项目实战概述&#xff1a;使用Spark RDD实现分组排行榜任务背景任务目标技术选型实现步骤1. 准备数据2. 数据上传至HDFS3. 启动Spark Shell4. 读取数据生成RDD5. 数据处理6. 计算TopN7. 输出结果8…

学习es6

1、let变量 2、const常量 3、解构赋值 4、模板字符串 5、简化对象写法 6、参数默认值 7、rest参数 8、扩展运算符 9、扩展对象方法 10、扩展数组方法 11、Set 12&#xff0c;Promise 13、Module模块

Leetcode - 周赛402

目录 一&#xff0c;3185. 构成整天的下标对数目 II 二&#xff0c;3186. 施咒的最大总伤害 三&#xff0c;3187. 数组中的峰值 一&#xff0c;3185. 构成整天的下标对数目 II 这里的T1&#xff0c;T2是一个题&#xff0c;这里直接一起讲了&#xff0c; 当我们已知 x%24 的值…

Postman接口测试工具

Postman接口测试工具是一款专为API测试设计的工具&#xff0c;其强大的功能和易用性使得它在现代Web开发流程中占据了重要地位。以下是对Postman接口测试工具的详细解析&#xff1a; 一、Postman简介 Postman是一个流行的API开发工具&#xff0c;它允许开发者快速创建、共享、…

深入理解Java虚拟机(JVM)中的垃圾回收器

垃圾回收&#xff08;Garbage Collection, GC&#xff09;是现代编程语言中用于管理内存的重要机制&#xff0c;特别是在Java虚拟机&#xff08;JVM&#xff09;中。 它的基本原理是自动检测和释放不再被程序使用的内存&#xff0c;以避免内存泄漏和提高程序执行效率。 1.GC的基…

MobileNetV3轻量化YOLOv8

1 轻量化模型 一般而言,模型轻量化有三个途径: 知识蒸馏:大模型引导小模型训练,让其逼近大模型效果 轻量化模块替换:利用一些轻量化模块进行替换,减少模型参数 剪枝:通过优化算法引导模型裁剪无用的参数 MobileNetV3论文如下,自行搜索 2 修改步骤 在nn/modules的文…

Cyberdog GPTS建立过程笔记

标题&#xff1a; Xiaomi Cyberdog 简介&#xff1a; Knowledge from Cyberdogs GitBook & part of GitHub source & lqxuezhang.cn. Knowledge captured on June 21st, 2024. Editor链接&#xff08;PlusAI的GPTS专用账号&#xff09;: https://cc01.plusai.io/gpts/e…

qt+halcon实战

注意建QT工程项目用的是MSVC&#xff0c;如果选成MinGW,则会报错 INCLUDEPATH $$PWD/include INCLUDEPATH $$PWD/include/halconcppLIBS $$PWD/lib/x64-win64/halconcpp.lib LIBS $$PWD/lib/x64-win64/halcon.lib#include "halconcpp/HalconCpp.h" #include &quo…

Kubernetes Ingress 简介

前言 Ingress 是 Kubernetes 中的一种资源对象&#xff0c;用于管理从集群外部到内部服务的 HTTP 和 HTTPS 路由。它提供了灵活的路由功能、SSL/TLS 终止、负载均衡和虚拟主机支持。Ingress 需要一个 Ingress 控制器来实际处理路由&#xff0c;并且可以通过配置不同的控制器来…

RedHat9 | Web服务配置与管理(Apache)

一、实验环境 1、Apache服务介绍 Apache服务&#xff0c;也称为Apache HTTP Server&#xff0c;是一个功能强大且广泛使用的Web服务器软件。 起源和背景 Apache起源于NCSA httpd服务器&#xff0c;经过多次修改和发展&#xff0c;逐渐成为世界上最流行的Web服务器软件之一。…

python开发基础——day7 序列类型方法

一、初识序列类型方法 序列类型的概念&#xff1a;数据的集合&#xff0c;在序列类型里面可以存放任意的数据&#xff0c;也可以对数据进行更方便的操作&#xff0c;这个操作是叫增删改查(crud) ( 增加(Creat)&#xff0c;读取查询(Retrieve)&#xff0c;更新(Update)&#xf…

蔚来汽车AI算法工程师,如何理解注意力?

大家好啊&#xff0c;我是董董灿。 今天分享一个上海蔚来汽车的AI算法岗位面试经验总结帖&#xff0c;面试岗位为算法工程师。 这次面试提到的问题&#xff0c;除了与实习相关内容和反问之外&#xff0c;面试官总共问了8个问题&#xff0c;主要集中在深度学习基础概念的理解上…

LeetCode.239滑动窗口最大值问题详解

问题描述 给定一个整数数组 nums 和一个整数 k&#xff0c;k 代表滑动窗口的大小&#xff0c;该窗口从数组的最左侧滑动到最右侧。你只能在滑动窗口内看到 k 个数字&#xff0c;每次窗口向右移动一位。要求返回每个滑动窗口中的最大值。 示例 考虑数组 nums [1,3,-1,-3,5,3…

共93本!全网最全Frontiers旗下期刊2022、2023版影响因子和分区对比完整版目录!

本周投稿推荐 SSCI • 1区&#xff0c;4.0-5.0&#xff08;无需返修&#xff0c;提交可录&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09; CNKI • 7天录用-检索&#xff08;急录友好&#xff09; SCI&EI • 4区生物医学类&#xff0c;0.1-0.5&…