0 前言
应用程序之间要想互相通信,一起配合来实现业务功能,还需传输协议支持。
传输协议就是应用程序之间对话的语言。设计传输协议,并无太多规范和要求,只需通信双方的应用程序都能正确处理该协议&&无歧义。
1 断句
1.1 分隔符
传输协议也是种语言,传输数据时,首要解决的就是断句。
对传输层,收到的数据是怎样的?
就是一段段的字节,但因网络不确定性,你收到的分段并不一定是生产者发出去的分段。
那在协议中也加上“标点符号”不就行?
而且,并不需要像自然语言中那么多种的标点符号,而只需定义一个分隔符即可。
这办法的确可行,很多传输协议就采用这种方法,比如HTTP 1.0协议,它的分隔符是换行(\r\n)。但这有个问题:自然语言中,标点符号是专用的,它没有别的含义,和文字天然区分。
但在数据传输过程,无论你定义什么字符作为分隔符,理论上都有可能会在传输的数据中出现。
那如何区分“数据内的分隔符”和真正的分隔符?
得在发送数据阶段,加上分隔符前,把数据内的分隔符转义,收到数据后再转义回来。
这的确是个麻烦过程,损失了一些性能。
1.2 预置长度
更加实用的方法。
给每句话前面加一个表示这句话长度的数字,收到数据时,按长度读。
如:03下雨天03留客天02天留03我不留
这里固定使用2位数字存放长度,每句话最长可支持99个字。接收后的处理就简单了,先读取2位数字03,知道接下来3个字是第一句话,那就等这3个字都收到,即可作为第一句话,同理读第二句话、第三句话。
这很好解决断句问题,实现比分隔符方法更简单,性能也更好,是普遍采用的分隔数据的方法。
redis 的 aof 文件好像就是前置长度哦,经典方案无处不在~
前置长度是不是也有类似问题呢,03也可能是正常文字里的内容,也是要转义
吧?
你可以想一下,最好自己实现一下接收数据进行解析的代码,你就会明白,前置长度无需转义。因为解析时,可明确知道当前读到的这个位置应该是长度还是真正数据,它不需要根据数据流中的内容来确定。