一、三层缓冲区
Packet
IoArgs
Frame
二、三者的管理者
Packet是AsyncSendDispatcher或者AsyncReceiveDispatcher
Frame是AsyncPacketReader或者AsyncPacketWriter
IoArgs比较模糊,IoArgs中持有了一个ByteBuffer,她是本次应该发送或者应该接收的数据的存储空间。
三、IoArgs持有的ByteBuffer,它承载了当前与网络最接近的缓冲区。这里的数据要么直接输出到网络要么直接从网络接收数据,所以它是最接近网络的缓冲区。但是,在发送的时候,首先要注册一个发送,然后由发送者调用接口,提供一个IoArgs,此时的IoArgs是由reader提供的。reader提供一个IoArgs到发送者后,发送者要将数据进行发送。至于发送成功或者失败则通过接口进行回调。对于写操作也是同样的流程。
当通过reader将数据填充到IoArgs后,交给Sender发送者,发送者发送一份数据的时候,会出现一定的问题,它有可能没有完全发送完当前IoArgs中的所有数据,它会进入到一个无限循环。
outputCallback就是一个输出,outputCallback是由线程池中的某一个线程调度的,会运行到相应的run方法。
它其实是一个runnable,在run方法中调用canProviderOutput()方法,也就是可以进行输出操作了。此时会进行数据的获取,拿到IoArgs。
拿到IoArgs之后进行写的操作,写道channel通道中去。 args.writeTo(channel).
写的时候有一个循环,必须把当前数据都写入进去后,才可以返回。
会通过IoProvider中的一个selector来告诉客户端是否可以发送数据,当可以发送的时候,也就是网卡就绪的时候,此时会进入写的状态,会把数据输出到SocketChannel当中,但是SocketChannel输出部分数据时,网卡把它的资源让给了另一个SocketChannel, 也就是当前一个SocketChannel写的操作,返回的长度可能是0。0不代表失败,只代表当前无法进行数据的输出操作。此时,正确的操作是,放弃当前的循环,重新注册selector,说还有数据没有发送完成,你需要在后面还可以发送数据的时候,重新调度我,让我继续发送数据。
如果强制输出,会导致的问题是,当前的socketchannel不能再发送数据了,真正可以发送的数据是由另外的socketchannel来完成的。但是占用的当前的线程,而其它可发送的socketchannel得不到线程的调度,也就影响了整个调度的性能。
所以,首先要改造的是SockeetChannelAdapter这边分,需要把当前的判断语句改造一下。
首先,拿到当前的返回值,如果为0表示当前是无法发送数据的。
再次判断是否还有数据输出,如果有,再次注册进行发送。如果没有数据输出了,则回调已经发送完成。
当再次注册的时候,它会重新加入到队列里面,重新注册一个selector。当它再次就绪的时候,会回到canProviderOutput(),此时会再次触发processor.provideIoArgs(),此时的IoArgs不是之前的IoArgs,它是一份新的IoArgs.
如果需要继续发送之前的那一份IoArgs,需要在callback中添加一个attach字段进行保存。
outputCallback修改为
writeTo方法由
改为
三、读取操作
inputcallback修改为
如果在readFrom中调用startReading()和finishReading()会导致上次接收的数据丢失掉,所以需改在AsyncReceiveDispatcher中调用
在调用新的IoArgs中调用开始写入数据的操作
在消费数据之前,调用已经完成写入数据的方法
在SocketChannelAdapter的inputCallback和outputCallback回调中,承载了第三层缓冲区消费或者说读取操作,当IoArgs中有数据或者说没有完全填充满的时候,将会通过callBack进行循环调度,直到它消费完成或者说全部填充完。
那么,在外部调度的地方,注册一个异步接收postReceiveAsync()或者注册一个异步发送PostSendAsync()中进行一下判断,判断一下当前附加部分是否为空,如果为空,代表为正确的状态,如果callback不为空,表明callback自身还在进行自循环,理论来说,不应该由外部来调用它来进行再次注册。