数据传输稳定性优化

项目地址:https://download.csdn.net/download/weixin_42528855/12549389

 

1.消息粘包:

实际:M1 和  M2 同时到达,并且被同时接收 ,最后才接收M3.

此时 M1 和  M2 就出现了消息粘包

2.消息不完整:

解决:

如何解决有序的混传数据:

三种方案:

提倡使用第二种:固定头部

 起止符方案:需要一个一个字节的依次检测(很耗费时间)

 头部的4个字节保证了后面的100个字节可以一次性传输,无需检查(可以避免消息粘包和丢失)

代码还是基于NIO的多人聊天室进行改动,但是对于多线程的部分没有进行改动:

1. 首先提供了一个  :公共的数据封装 类:

 

为什么会使用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,如果没有发完,则继续发送当前包。

 

总结:

发送和接收的流程:

猜你喜欢

转载自blog.csdn.net/weixin_42528855/article/details/106902295