二进制协议与文本协议
二进制协议 VS 文本协议
前言
最近由于工作上的需要(一方面是与底层与传感器进行数据交互,另一方面是对RabbitMQ的AMQP协议的学习),接触了一些网络协议相关的内容。正好就二进制协议与文本协议的一些问题简单说一些。
二进制协议(binary protocol)
概念
协议:就是一组大家约定俗成的契约,大家都遵守。而计算机领域的协议,大多指的就是网络协议。
网络协议:计算机网络中进行数据交换而建立的规则、标准或约定的集合。说直白点,就是大家约定XXX网络协议下的数据怎么接收,怎么处理,怎么发送等。
二进制协议(Binary protocol):
Wiki: A binary protocol is a protocol which is intended to be read by a machine rather than a human being, as opposed to a plain text protocol such as IRC, SMTP, or HTTP/1.1. Binary protocols have the advantage of terseness, which translates into speed of transmission and interpretation.
Binary protocol is also used in the context of a protocol between exactly two parties, in contrast to a multi-party protocol. Binary protocol, or binary collaboration have been used in the terminology of standards such as EbXML, HTTP/2 and EDOC.[1] An interface in UML [2] may also be considered a binary protocol.
简单来说,就是二进制协议在进行网络传输时,传输的并不是类似JSON这样的文本文件,而是类似BSON这样的二进制数据。
(Java中字节流采用的是ASCII码,而字符流采用的是Unicode码)
优点
- 空间占用小(包括内存,带宽等)
- 运算规则简单(如加密就方便)(毕竟来来回回就0和1)
- 可靠性高(不是0就是1,还有校验和等技术实现验证。文本协议与之对应的就是数字签名)
- 部分技术场景实现方便(典型的底层硬件,如传感器。因为底层本就是0和1构成的数据,不需要转换)
缺点
- 可读性差(由此延伸出记忆困难等问题,毕竟位数太多了,还全是0和1,就是机器码啊。所以协议的每条命令都要有对应的文档进行细致说明,包括二进制文件采用的是哪种编码方式等)
- 扩展性差(并不是不可以进行消息的扩展,而是已经确定的数据解析顺序,是不可以改变的)
- 无法跨处理器(据说是由于严格的内存到对象的转换。个人的理解是,由于不同处理器架构存在数据存储的大端小端问题而导致的。)
- 部分技术场景实现复杂(例如,原先只要通过JSON,就能获取所需数据。而现在,你首先要获取二进制流,可能还需要进行拆包与粘包工作,从而获得二进制数据。再根据协议,一条条地解析命令字与数据域。不要问我为什么这么清楚,说多了,都是泪。之后有机会,会讲解一下的)
举个栗子
TCP:一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。
首先,我们从网络模型的角度来考虑。TCP位于传输层,接收上一层的数据,对数据进行必要的分割,并将数据交给网络层,且保证这些数据的准确到达(三次握手)。所以,作为传输层的协议,TCP主要任务是传输与数据分割。那么很明显,采用二进制数据进行传输时最好的选择。传输层能够充分发挥二进制协议空间占用小(带宽消耗低),可靠性高(提高数据传输的可靠性),运算规则简单(便于数据的分割等工作)等优点。并由于传输层特性,降低了其缺点所带来的影响。说到这里,不得不说层次架构是个好东西,其典型代表的网络模型,更是如此。其次,了解TCP报文结构的朋友想象一下。如果TCP不是二进制协议,而是一个文本协议,那么其中的TCP Flags,Checksum等的实现会不会变得冗余,繁琐。所以,TCP是一个二进制协议。与此同时,TCP协议也是二进制协议的一个典型代表。
其他:UPD,IP,PPP,Protobuf,MQTT,AMQP等典型例子类比分析即可,不再赘述。
使用场景
相对于文本协议而言,二进制协议的自定义更具区分度,数量也更多。原因也很简单,正如之前所说,二进制协议相对文本协议扩展性更差,可读性更差,这也就造成其复用性很差。往往不同产品,项目间的二进制协议差别也许不大(本来就是比较底层的东西,没有太高的复杂性),但就是不能共用(也许就是协议中,数据的标示符,命令字等区域位置,长度有所不同)。所以,二进制协议的自定义较为常见。
以自身为例,我负责的物联网项目中的终端程序需要与不同传感器进行交互。而大多第三方的硬件厂商并不会采用诸如MQTT这样的网络协议,他们往往会自定义一个二进制协议,来与上层通信(毕竟硬件实现MQTT这样的标准化协议,也是需要成本投入的)。例如我解决交互的第一个传感器526,其实通过串口通信(这个,有点古老)。它的数据帧是这样的:
很明显,这样的规定很是“死板”,Java中,通过RXTX监听对应串口,并接收数据数组(这里可能涉及到数据的粘包,拆包工作。当然,如果数据接收频次不高,并且不是连续数据,可以通过sleep或wait等来暂停一下,确保数据接收完毕)。之后,根据第三方厂商所给数据帧格式,对命令,数据域进行解析(这里就必须很死板地根据对应位置读取对应数据,另外数据域可能采用BCD码)。最后根据命令字,对数据进行相关操作。
这个时候,我们再看一下,同一厂商下同一产品线,型号略有不同的产品826,它的数据帧与前面的526其实差不过。
但是,两者的区别在于,前者数据域的每个数据都是三个字节的,而后者则是四个字节的。所以得重写。当然,如果接入的第三方自定义协议越多,就越好做抽象,从而达到一定的复用(当然,效果肯定是不能和文本协议相比较的)。
文本协议(Text-based protocol)
概念:
文本协议(Text-based protocol):
Wiki:A text-based protocol or plain text protocol is a communications protocol whose content representation is in human-readable format.
The immediate human readability stands in contrast to binary protocols which have inherent benefits for use in a computer environment (such as ease of mechanical parsing and improved bandwidth utilization).
简单来说,就是文本协议在进行网络传输时,传输的是类似JSON,XML这样的文本文件,而不是二进制文件(就是0和1)
概念扩展:
一般来说,这个时候,就该有人要抬杠了。一般可以分为两种,这里我们就HTTP这一文本协议为例子讨论。第一种,有人提出HTTP协议的底层依旧是0和1,它怎么就是文本协议了。答案就是一个协议是不是文本协议,与它在网络模型的上下层协议无关,只与自身相关。第二种,有人提出HTTP可以用来传输图片(写过类似NODE.JS服务器原始请求,就是返回值类型,需要专门指定。会明白图片传输是采用二进制的),那么HTTP还能算文本协议嘛。答案就是它是不是文本协议,取决于它是否能够利用文本的格式来进行通信,很明显它可以,所以它是文本协议。这也避免有人拿telnet能进行二进制通信来抬杠。当然,国外也有人提出是不是文本协议不取决于它能否对二进制数据进行编码(UTF,ASCII),而是取决于协议是围绕数据结构,还是文本字符串。最后,上述HTTP协议是指HTTP1.1,而HTTP2是二进制协议(根据这点,国外那位的观点,需要稍作修改:在传输的数据是否具备数据结构)。
优点&缺点
二进制协议的优缺点转换一下就OK了,不在赘述。
举个栗子
HTTP1.1:基于请求-响应模型,无状态,无连接的应用层协议。
其他:FTP,TELNET等。
使用场景
乍一看,貌似平时大家开发的协议貌似大多是二进制协议,什么RPC,AMQP,就连Kafka都是基于TCP自写的二进制协议。不过之前就说了,二进制协议缺乏复用性,所以多是肯定的嘛。但是用得最多的还是HTTP这样的文本协议。平时前后端进行的交互,就是基于HTTP的,也就是文本协议的。一般来说,我们直接用的都是文本协议,即使涉及二进制协议,也是对二进制协议进行了一定封装(如kafka的java API,AMQP的API)后的调用。
总结
多数情况下,很多人可以写了好几年都碰不到几回二进制协议,但是一旦进了二进制协议的坑(一方面是物联网中与硬件交互,另一方面是研究什么MQ的通信协议啊),然后就只能说一句,真香。
好吧,开个玩笑。其实两种协议各有利弊,没有银弹,只有适用场景。说几个主要的考虑点,首先从成本(包含学习成本,时间成本等)来看,文本协议肯定是优于二进制协议的,否则,也不会那么多人不了解二进制协议了。其次从效率(包括带宽等资源消耗,数据处理等)来看,二进制协议肯定是优于文本协议的,否则,也不会那么多MQ采用二进制协议了。然后从可读性来看,文本协议肯定是由于二进制协议的,当然这也带来了学习成本(包括熟悉二进制协议,如数据帧等)。最后从扩展性与安全性来看,二进制协议虽然有一定扩展性,导致开发的时间成本上升。但我认为如果数量较多,形成协议族效果,其实成本也就没那么高了(毕竟二进制协议中很多工具是通用的,数量优势也可以完成良好的抽象)。安全性方面,二进制协议有天生的优势(全是0和1),其编码规则只有收发双方了解,加解密也方便。