2 双工收发
2.1 单工通信
任一时刻,数据只能单向传输,一个人说时,另一个人只能听。
HTTP 1.0协议就是这样,客户端与服务端建立个连接后,客户端发个请求,直到服务端返回响应或请求超时,这段时间内,这个连接通道上不能再发其他请求。
这种单工通信,效率低,很多浏览器和APP为解决性能问题,只能同时在服务端和客户端间创建多条连接。
单工通信时,一句对一句,请求和响应按序依次收发,有个天然对应关系。就像被女朋友质问时,女朋友问一句,你才敢答一句。这沟通效率有何意义?
2.2 双工通信
而TCP连接是全双工通道,可同时进行数据的双向收发,互不影响。要提高吞吐量,应用层协议必须支持双工通信。
双工通信,不管是客户端还是服务端建立好连接后,双方都能基于该socket进行收发消息,而不是服务器只能accept到message后才能做些处理。
如果说你和你对象有边听边说的本事,换成双工协议后,基本就是在和女人讲道理,你们就会混乱到分不清到底在回答问题or陈述观点。
并发下,顺序也无法保证。实际设计协议时,一般不关心顺序,只需确保请求和响应能够正确对应。
解决对应问题
发送请求时,给每个请求加个序号:该序号在本次会话内保证唯一,然后在响应中带上请求的序号,这就能把请求和响应对应上。
加上序号后,即使如抢答一般混乱,也分得清到底在说啥。
你和你对象就能对自己发出去的请求来编号,回复对方响应的时候,带上对方请求的编号即可。这就解决了双工通信的主要问题。
在一次会话过程中,开头的先是唯一序列号吗?然后后面跟数据长度,再是内容吗?
那接到消息的一方,如何分辨序列号的长度大小,做到区分序列号和内容前的数据长度信息?
开头就肯定是数据长度,序号也是数据的一部分!所以应该在数据长度的后面。
3 总结
设计传输协议时,只要双方应用程序能够识别传输协议,互相交流即可,并没啥绝对的规范。
首要得解决断句,有“分隔符”和“前置长度”两种断句方案。
使用ID来标识请求与响应对应关系的方法,是比较通用的实现双工通信的方法,可有效提升数据传输的吞吐量。
解决了断句,实现了双工通信,配合专用序列化方法,即可实现高性能的网络通信协议,实现高性能的进程间通信。很多MQ、RPC框架都是用这种方式来实现它们自己的私有应用层传输协议。
简单的高性能通信程序:你和你对象三组对话,服务端是你对象,客户端是你自己,让俩人在客厅碰见一百万次,记录下总共耗时。
https://github.com/WangYangA9/netty-FullDuplex-example