0前言应用之间如果要相互通信,协同合作实现业务功能,同样需要传输协议的支持。传输协议是应用程序相互交谈的语言。设计一个传输协议并没有太多的规范和要求,只要通信双方的应用能够正确处理协议&&没有歧义即可。1分句1.1分隔符传输协议也是一种语言。传输数据时,第一个问题是句子分割。对于传输层来说,接收到的数据是什么样子的?它是一段字节,但由于网络的不确定性,你收到的段不一定是生产者发送的段。协议上加上“标点符号”不就可以了吗?而且不需要像自然语言那么多的标点符号,只需要定义一个定界符即可。这种方法确实可行,很多传输协议都采用这种方法,比如HTTP1.0协议,其定界符是换行符(\r\n)。但是有一个问题:在自然语言中,标点符号是特殊的,它没有其他意义,自然地与文本区分开来。但是在数据传输的过程中,无论你定义什么字符作为分隔符,理论上都可能出现在传输的数据中。那么如何区分“数据内部的定界符”和真正的定界符呢?在发送数据阶段,数据中的定界符必须在加定界符前进行转义,收到数据后再进行转义。这确实是一个麻烦的过程,并且损失了一些性能。1.2更实用的预置长度方法。在每句前面加一个表示句子长度的数字,接收数据时根据长度读取。如:03下雨天03客人日02日住宿03我不在这里固定使用2位数字存储长度,每句话最多支持99个字符。接收后的处理很简单,先读取2位数字03,知道接下来的3个字是首句,然后等这3个字接收到,就可以作为首句了,读入同理第二句,第三句。这是一个很好的解决句子分割问题的方法。它比定界符方法实现起来更简单,性能也更好。它是一种常用的数据分离方法。redis的aof文件好像是pre-length。经典方案无处不在~前置长度有没有类似的问题?03也可能是普通文本中的内容,一定要转义吧?大家可以想一想,接收数据解析的代码最好自己实现,就明白pre-length不用转义了。因为在解析的时候可以很清楚的知道当前读取的位置应该是长度还是真实数据,不需要根据数据流中的内容来判断。2双工收发2.1单工通信在任何时刻,数据只能单向传输。当一个人说话时,另一个人只能听。HTTP1.0协议是这样的。客户端与服务器建立连接后,客户端发送请求,直到服务器返回响应或请求超时。在此期间,连接通道上不能发送其他请求。这种单纯的通信是低效的。很多浏览器和APP为了解决性能问题,只能在服务端和客户端同时创建多个连接。单纯形通信,一句话就是一句话,请求和响应依次发送和接收,自然对应。就像被女朋友追问,女朋友一问你就敢回答。这个沟通效率是什么意思?2.2双工通信TCP连接是一个全双工通道,可以同时在两个方向发送和接收数据,互不影响。为了提高吞吐量,应用层协议必须支持双工通信。双工通信,无论客户端还是服务端建立连接,双方都可以基于socket发送和接收消息,而不是服务端接受消息后只能做一些处理。如果你和你的另一半有边听边说的能力,换成双工协议后,基本上就是在和女人讲道理,会糊涂得分不清是在回答问题还是在回答问题。陈述你的观点。并发下,不能保证顺序。在实际设计协议时,一般不关心顺序,只要保证请求和响应能够正确对应即可。解决对应问题发送请求时,为每个请求添加序号:保证序号在本次session内唯一,然后在response中带上请求的序号,可以对应request和回复。添加序列号后,即使像抢答一样混乱,也能说出自己在说什么。你和你的伙伴可以给你发出的请求编号,当你回复对方的回复时,带上对方要求的编号即可。这解决了双工通信的主要问题。在会话期间,它是否以唯一序列号开头?然后是数据的长度,然后是内容?接收报文的一方如何区分序号的长度,从而区分序号和内容之前的数据长度信息?开头一定是数据长度,序号也是数据的一部分!所以它应该在数据长度之后。3小结在设计传输协议时,只要双方的应用能够识别传输协议并相互通信即可,没有绝对的规范。首先,必须解决句子分割问题。分句方案有两种:“分隔符”和“预长”。利用ID来标识请求和响应的对应关系的方法是实现双工通信的一种比较常用的方法,可以有效提高数据传输的吞吐量。解决了分段,实现了双工通信,用专用的序列化方法可以实现高性能的网络通信协议和高性能的进程间通信。很多MQ和RPC框架都是通过这种方式来实现自己私有的应用层传输协议。简单的高性能通信程序:你和你的伙伴进行三段对话,服务器是你的伙伴,客户端是你自己,让两人在客厅见面一百万次,记录总耗时。https://github.com/WangYangA9...https://sourcegraph.com/github...
