#三更半页 数据是如何进行传输的?看看网络传输层的抽象。
区别于client端和server端。当建立连接时,
client端创建的是阻塞式的BioWritableChannel;
server端创建的是非阻塞式的NioWritableChannel。先看简单的client端的处理——
client端的WritableChannel创建时发送、读取都基于Soket对象的input流和output流。
read方法需要实现,接受一个连接对象,主要用例handle网络对象(NetBuffer);
wirte方法接受的对象也是NetBuffer
client端发送数据:send方法(构造并添加回调函数,这个回调会在收到response时被调用)
第一:构造输出流 TransferOutputStream ,这里的out对象是DataOutputStream,底层的outstream流是自定义的ResettableBufferOutputStream,这里维护了NetBuffer的对象buffer,其中又包含了DataBuffer对象,后者是最终利用ByteBuffer来管理数据的写入和读取。所以层次结构如下——
TransferOutputStream (l.net)
-->DataOutputStream(resettableOutputStream) (java.io)
---->NetBufferOutputStream (l.net)
------> NetBuffer (l.net)
-------->DataBuffer (l.common)
---------->ByteBuffer (java.nio)
第二:对数据包进行编码。包含 header 和 data 数据。(不同协议包进行不同的encode)
第三:利用TransferOutputStream flush方法发送数据:
writePacketLength(); // 写如包大小 int值
buffer.flip(); // 翻转buffer,从写入模式进入读取模式
writableChannel.write(buffer); // 准备发送
第四:利用TansferConnection中的WritableChannel里的socket对象进行发送
client端是阻塞模式,所有直接从通道中准备读取数据——
tcpConnection.getWritableChannel().read(tcpConnection);
包括以下几步:
第一:读取长度,
第二:根据长度,构造DataBuffer对象并设置limit大小
第三:获取byteBuffer,从socket中读取指定大小数据
第四:构造NetBuffer对象
第五:处理对象 conn.handle(netBuffer);
handle的实现都是在TansferConnection中,但对应client来说这里是收到了server端的响应,handleResponse即可(在TcpClientConnection中重写处理;对应的handleRequest 在TcpServerConnection中处理)
TransferInputStream对象也是基于NetBuffer来构造的 ,并且实现了NetInputStream接口
new DataInputStream(new NetBufferInputStream(inBuffer));
处理逻辑:
第一:确保返回的status正确
第二:没有异常信息
第三:根据packetId获取回调函数(必须有回调,在执行send方法发送前会构造并添加这个回调函数到clientConnection中)
回调本身定义了run方法;调用runInternal(NetInputStream in) 方法,然后在回调中重写,实际执行的是
// this is an AsyncCallback
handleAsyncCallback(in, packet.getAckType(), ackPacketHandler, this);
最终在这个方法中根据packet类型获取解码器,对数据进行解码(每个协议包都有一个对应的解码器,在应用启动时就完成了注册)
这样完成第一次协议包的交互:SessionInit 和 SessionInitAct,最终创建完成了ClientSession。 https://asia.feed.base.one/posts/de2a73e4-d2e1-489f-a334-e2e077b2f1c5