tio服务端WsServerStarter初始化逻辑
关键类
AioHandler
|------WsServerAioHandler
AioListener
|------WsServerAioHandler
TioConfig
|------ServerTioConfig
|------ClientTioConfig
HttpConfig
|------WsServerConfig
IWsMsgHandler(自定义继承实现)
WsTioUuid(雪花算法生成uuid)
TioServer
CompletionHandler<AsynchronousSocketChannel, TioServer>
|------AcceptCompletionHandler(服务通道启动后,客户端数据包准备就绪后会执行completed方法)
tio源码初始化逻辑
tio服务端start方法执行逻辑
关键类
服务端启动,涉及到AIO相关概念。
AsynchronousServerSocketChannel:ServerSocket的aio版本,创建TCP服务端,绑定地址,监听端口等。
AsynchronousSocketChannel:面向流的异步socket channel,表示一个连接。
AsynchronousServerSocketChannel和AsynchronousSocketChannel能够绑定到一个制定线程池的组中,这个线程池能够用future或者CompletionHandler来对执行结果进行处理。
AsynchronousChannelGroup
异步channel的分组管理,目的是为了资源共享。一个AsynchronousChannelGroup绑定一个线程池,这个线程池执行两个任务:处理IO事件和派发CompletionHandler。AsynchronousServerSocketChannel创建的时候可以传入一个AsynchronousChannelGroup,那么通过AsynchronousServerSocketChannel创建的 AsynchronousSocketChannel将同属于一个组,共享资源。
CompletionHandler:用户处理器
异步IO操作结果的回调接口,用于定义在IO操作完成后所作的回调工作。AIO的API允许两种方式来处理异步操作的结果:返回的Future模式或者注册CompletionHandler,推荐用CompletionHandler的方式,这些handler的调用是由AsynchronousChannelGroup的线程池派发的。显然,线程池的大小是性能的关键因素。AsynchronousChannelGroup允许绑定不同的线程池,通过上面三个静态方法来创建,需要根据具体应用相应调整,从框架角度出发,需要暴露这样的配置选项给用户。
aio服务启动核心逻辑
使用AsynchronousChannelGroup.withThreadPool(线程池);方法创建一个AsynchronousChannelGroup 。再用AsynchronousServerSocketChannel.open(AsynchronousChannelGroup _);方法在线程池中打开一个socket通道。设置套接字__SO_REUSEADDR,SO_RCVBUF=_64 M。将通道绑定ip和端口号。使用accept方法等待客户端连接后,调用handle中的completed方法。
tio源码start逻辑
服务器等待客户端的建立
大致流程逻辑是,一、首先判断客户端是否在黑名单中。serverTioConfig里保存了socket服务端相关的配置信息执行中涉及到的比较重要的属性:
1.AcceptCompletionHandler(服务端接收到客户端消息时处理逻辑)。
2.ServerAioListener(消息监听器,也就是服务端在处理每一步的时候,调用listener中的方法。类似处理消息时候的生命周期)。
serverTioConfig的父类TioConfig 中流程中涉及到比较重要的参数:
1.Ids 中含有一个带有读写锁的MapWithLock<String, ChannelContext>属性,处理消息的时候获取服务端的channelContext的id,当成key对应的ServerChannelContext当成属性,保存在MapWithLock的变量中。
2.Ips 中含有MapWithLock<String, SetWithLock>的属性值,当解析完客户端ip和服务端的ip封装成node对象后,将ServerChannelContext绑定到该对象下,绑定逻辑为:先通过clientip获取Map对象中的value值,也就是SetWithLock,如果为null证明第一次绑定,直接将ServerChannelContext对象放入到Ips的属性中。如果不为空,等待获取Ips对象的锁,当获取到的锁后,开始执行业务逻辑,如果这时候获取的ChannelContext还是空,证明是集群环境下的另外服务节点。new一个SetWithLock对象,并调用CluClient.bindXxx(该方法为空方法,不清楚是干啥的)
最后,统一将ServerChannelContext设置到Set对象中。同一个client的ServerChannelContext覆盖操作。
二、创建一个ReadCompletionHandler、WriteCompletionHandler。分别用于读取消息和写出消息。
三、创建ServerChannelContext用于保存serverTioConfig、构建serverNode(ip+port)和clientNode(ip+port)、ips。
四、使用ReadCompletionHandler处理客户端通道消息。当接收到消息后会调用completed方法解析缓冲区中的数据。
服务器的消息处理(重要)
使用ReadCompletionHandler进行通道消息解析,tio处理闭包、粘包就是使用这个类WsServerDecoder。
业务处理过程如图所示:
关键类详解:
- ReadCompletionHandler 一个消息包的缓冲区读到后会执行completed方法,值得注意的是,第一次执行用于客户端与服务器进行握手,将http升级为ws协议。当数据包过大的时候会将其拆分为多个缓冲区包进行发送,n-1的缓冲区大小默认为30720b(30kb)。
- DecodeRunnable 使用这个类保存半包传输时候,将上次的半包数据保存到**lastByteBuffer **变量中,用于下一次包的数据过来时,累加构建成一个新的缓冲区。值得注意的是 tio在源码编写的时候,设置了半包的数量,如果数量大于10后进行满包攻击,抛出异常。
- WsServerAioHandler 用于封装消息类型,调用WsServerDecoder中_decode_方法_。_等待IWsMsgHandler的消息业务处理。
- WsServerDecoder _decode_方法用于解析缓冲区中的数据,用位移计算,去掉mark,将消息体彻底读取出来。关键性的逻辑是半包的时候,读取缓冲区的长度会< 缓冲数据的总长度时,返回空将半包的缓冲区数据保存在lastByteBuffer 中 ,等待下一个半包数据过来时,执行2的逻辑。直到读取缓冲区的长度=缓冲数据的总长度。
- HttpRequestDecoder 握手时候将http协议升级为ws协议。
- WsServerAioListener(AioListener) 业务实现该类,消息接收会调用该监听类中的onafterReseviedBytes方法和onafterDecode方法。
- IWsMsgHandler 业务实现类,aio处理完数据后,会调用IWsMsgHandler 实现类中的onBytes(接收到了二进制数据)onText(接收到文本数据)等
6和7 是业务中必须创建的实现类。
DecodeRunnable子任务
如果ServerTioConfig中配置了useQueueDecode=ture时,则使用队列方式进行解码
解码任务待整理…敬请期待
HandlerRunnable子任务
敬请期待…
SendRunnable子任务
敬请期待…