你好,我是何小锋。上一讲我分享了RPC原理,其核心是让我们像调用本地一样调用远程,帮助我们的应用层屏蔽远程调用的复杂性,使得我们可以更加方便地构建分布式系统。总结起来,其实就一个关键字:透明化。
接着上一讲的内容,我们再来聊聊RPC协议。
一提到协议,你最先想到的可能是 TCP协议、UDP协议等等,这些网络传输协议的实现在我看来有点晦涩难懂。虽然在RPC中我们也会用到这些协议,但这些协议更多的是对我们上层应用是透明的,我们RPC在使用过程中并不太需要关注他们的细节。那我今天要讲的RPC协议到底是什么呢?
可能我举个例子,你立马就明白了。HTTP协议是不是很熟悉(本讲里面所说的HTTP默认都是1.X)? 这应该是我们日常工作中用得最频繁的协议了,每天打开浏览器浏览的网页就是使用的HTTP协议。那HTTP协议跟RPC协议又有什么关系呢?看起来他俩好像不搭边,但他们有一个共性就是都属于应用层协议。
所以**我们今天要讲的RPC协议就是围绕应用层协议展开的。**我们可以先了解下HTTP协议,我们先看看它的协议格式是什么样子的。回想一下我们在浏览器里面输入一个URL会发生什么?抛开DNS解析暂且不谈,浏览器收到命令后会封装一个请求,并把请求发送到DNS解析出来的IP上,通过抓包工具我们可以抓到请求的数据包,如下图所示:
![](https://static001.geekbang.org/resource/image/5c/99/5ca698cbdc61b8e8b090773406b3ab99.jpg)
## 协议的作用
看完HTTP协议之后,你可能会有一个疑问,我们为什么需要协议这个东西呢?没有协议就不能通信吗?
我们知道只有二进制才能在网络中传输,所以RPC请求在发送到网络中之前,他需要把方法调用的请求参数转成二进制;转成二进制后,写入本地Socket中,然后被网卡发送到网络设备中。
但在传输过程中,RPC并不会把请求参数的所有二进制数据整体一下子发送到对端机器上,中间可能会拆分成好几个数据包,也可能会合并其他请求的数据包(合并的前提是同一个TCP连接上的数据),至于怎么拆分合并,这其中的细节会涉及到系统参数配置和TCP窗口大小。对于服务提供方应用来说,他会从TCP通道里面收到很多的二进制数据,那这时候怎么识别出哪些二进制是第一个请求的呢?
这就好比让你读一篇没有标点符号的文章,你要怎么识别出每一句话到哪里结束呢?很简单啊,我们加上标点,完成断句就好了。
同理在RPC传输数据的时候,为了能准确地“断句”,我们也必须在应用发送请求的数据包里面加入“句号”,这样才能帮我们的接收方应用从数据流里面分割出正确的数据。这个数据包里面的句号就是消息的边界,用于标示请求数据的结束位置。举个具体例子,调用方发送 AB、CD、EF 3 个消息,如果没有边界的话,接收端就可能收�