作者:__wolf狼 | 来源:互联网 | 2023-06-24 14:53
1.消息粘包:实际:M1和M2同时到达,并且被同时接收,最后才接收M3.此时M1和M2就出现了消息粘包2.消息不完整:解决:如何解决有序的混传数据:三种方案:提倡使用第二种:固定头
项目地址:https://download.csdn.net/download/weixin_42528855/12549389
1.消息粘包:
![](https://img8.php1.cn/3cdc5/12d98/882/03f0b0796af7d1dd.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
![](https://img8.php1.cn/3cdc5/12d98/882/868252d2073d6c49.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
实际:M1 和 M2 同时到达,并且被同时接收 ,最后才接收M3.
此时 M1 和 M2 就出现了消息粘包
2.消息不完整:
![](https://img8.php1.cn/3cdc5/12d98/882/ccd65b51d968398c.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
![](https://img8.php1.cn/3cdc5/12d98/882/b861a0dfef46c396.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
![](https://img8.php1.cn/3cdc5/12d98/882/b99a3afa0b43a8b1.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
解决:
如何解决有序的混传数据:
三种方案:
![](https://img8.php1.cn/3cdc5/12d98/882/bb1922f5320886a0.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
提倡使用第二种:固定头部
![](https://img8.php1.cn/3cdc5/12d98/882/140b77cc3de6414e.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
起止符方案:需要一个一个字节的依次检测(很耗费时间)
![](https://img8.php1.cn/3cdc5/12d98/882/89ba54fa21c98c8d.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
头部的4个字节保证了后面的100个字节可以一次性传输,无需检查(可以避免消息粘包和丢失)
代码还是基于NIO的多人聊天室进行改动,但是对于多线程的部分没有进行改动:
1. 首先提供了一个 :公共的数据封装 类:
![](https://img8.php1.cn/3cdc5/12d98/882/7662e9d4c49f5963.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
为什么会使用packet?
这里的主要目的是构建3层缓存,对于发送的数据是多样性的,我们需要一个统一的封装,Packet就是不错的选择。
当我们在发布数据之前会先封装为统一的Packet,Packet可以提供基础的Stream操作,随后会到达第二层,也就是Frame层,将一个包转化为不同的帧。对于包和帧都是有意义的,有实际的反向解析操作。
当我们到达真实需要发送的位置会将帧转化为IoArgs,此时就没有上层业务意义了,更多的是数据的载体。
这样的方式可以做到3层缓冲,同时也可针对不同层面做不同的调度,这也增加整体的框架调度性能。
接收消息:
2. 分析一下 AsyncReceiveDispatcher 类(处理 StringReceivePacket的类【ReceivePacket的子类】 )
在 AsyncReceiveDispatcher 类 中 关注 两个函数:
start() 和 registerReceive()
在 registerReceive() 中启动了 接收者的 receiveAsync(ioArgs); 异步接收类,
注意:start() 是在 Connector 类中的 setup函数里 启动的:
// 启动接收
receiveDispatcher.start();
receive涉及了三个回调: 这是慕课网上一位 昵称为:慕勒1089785 的大佬总结的
这三个回调基本就完成了数据接受的一个过程
第一个就是 上级SocketChannelAdapter实现了HandlerproviderCallback的接口,并且将其注册到了IoSelectorProvider之中,当可以处理数据时,下层就回调了接口中的方法。上级就让其来真正的实现接受。如用IoArgs来读取数据之类的。
第二就是,上层ReceiverDispatcher实现了IoArgsEventListener接口,并在SocketChannelProv中注册了,当下层IoArgs读取到数据之后,就会回调给上层,ReceiverDispatcher就会处理这个IoArgs,打包成Packet。
第三就是,Connector实现了一个回调接口,并在ReceiverDispatcher注册了,当下层Packet打包完成之后,就会回调给上层,让Connector打印数据。(Server还需要广播)。
发送消息:
发送消息相对于 接收消息 要简单一些,但是也涉及到了回调函数:
第一个就是 上级SocketChannelAdapter实现了HandleOutputCallback的接口,并且将其注册到了IoSelectorProvider之中,当可以处理数据时,下层就回调了接口中的方法。上级就让其来真正的实现接受。将写线程交给线程池来处理。
第二就是,上层AsyncSendDispatcher实现了IoArgsEventListener接口,并在SocketChannelProv中注册了,当下层IoArgs读取完Packet数据之后,就会回调给上层,ReceiverDispatcher就会处理这个IoArgs,如果没有发完,则继续发送当前包。
总结:
![](https://img8.php1.cn/3cdc5/12d98/882/47ba7ddba4060240.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
发送和接收的流程:
![](https://img8.php1.cn/3cdc5/12d98/882/15b8ace7ed494ef2.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)
![](https://img8.php1.cn/3cdc5/12d98/882/bc6971b06898a444.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjUyODg1NQ==,size_16,color_FFFFFF,t_70)