于是我上网搜索。 很多解释都很官方相信大家都在各种平台看过解释了一下,好像没什么解释的都是在用一个我们不知道的概念去解释另一个我们不知道的概念懂的不用看不懂的...
于是我上网搜索。
很多解释都很官方相信大家都在各种平台看过解释了一下,好像没什么解释的都是在用一个我们不知道的概念去解释另一个我们不知道的概念懂的不用看不懂的人还是不懂
这种看得到看不到的感觉,在雾里似乎很难受我明白
为了避免大家强烈的审丑疲劳,今天我们试着换一种方式来说。
从TCP开始。
作为程序员,假设我们需要从计算机A的进程向计算机B的进程发送一条数据,我们通常使用socket在代码中编程。
这个时候我们的选项一般是TCP和UDPTCP可靠,UDP不可靠除非是神级程序员宗,只要对可靠性有一些要求,普通人一般是无脑选择TCP的
类似这样的。
fd =插座,
SOCK_STREAM是指使用字节流传输数据,这是TCP协议。
定义完socket之后,我们就可以愉快地操作socket了,比如用bind绑定IP端口,用connect发起连接。
握手连接建立过程
连接建立后,我们可以使用send发送数据,使用recv接收数据。
就这么一个赤裸裸的TCP连接就能收发数据,这还不够吗。
不会,这种使用会有问题。
使用裸TCP有什么问题。
TCP有三个特点:面向连接,可靠和基于字节流。
什么是TCP。
这三个特点真的总结的非常精辟这个八股文我们没有白背
每个特性开发可以讲一篇文章,今天需要重点讲一下字节流。
一个字节可以理解为在双向通道中流动的数据这个数据其实就是我们常说的二进制数据简单来说就是很多01串裸TCP收发的这些01字符串之间没有边界,你不知道一个完整的消息在哪里
01二进制字节流
因为这种无边界的特性,当我们选择通过TCP发送夏洛特和非常苦恼时,接收方接收到的是再见失败者先生,此时接收方并不会告诉你是想表达夏洛特+非常苦恼还是夏洛特
消息比较
这就是所谓的贴袋问题,我之前也专门写过一篇文章讲过这个问题。
这样做的目的是告诉你,纯裸TCP是不能直接使用的您需要在此基础上添加一些自定义规则来区分消息边界
所以我们会把每一条要发送的数据打包,比如添加到消息头消息头清楚地说明了一个完整数据包的长度按照这个长度,我们可以继续接收数据截取后,它们才是我们真正要传递的消息体
消息边界长度标志
而且这里说的消息头也可以放各种东西,比如消息体是否压缩过,消息体的格式,只要上下游都约定好了,互相认可这就是所谓的协议
每个使用TCP的项目都可能定义一组这样的协议解析标准它们可能不同,但原理是相似的
让我们回头看看网络的层次图。
四层网络协议
和RPC,也称为远程过程调用它本身不是一个特定的协议,而是一个调用方法
例如,我们通常像下面这样调用一个局部方法。
res =局部函数
现在,如果这不是一个本地方法,而是一个远程服务器暴露的方法remoteFunc,如果我们还能像本地方法一样调用它,屏蔽掉一些网络细节,使用起来更方便,岂不是很美好。
res=remoteFunc
RPC可以像调用本地方法一样调用远程方法。
基于这种想法,老板们创造了许多风格的RPC协议,如众所周知的gRPC和thrift。
在这里,让我们回到文章的标题。
现在电脑上安装的各种联网软件,如xx管家,xx卫士等,都需要作为客户端与服务器建立连接来收发消息此时,它们都使用应用层协议在这种客户端/服务器架构下,他们可以使用自己的RPC协议,因为连接自己公司的服务器是可以的
好像又回到文章开头了,要从两者的区别说起。
服务发现
首先,要向服务器发出请求,你得建立连接,而建立连接的前提是你得知道IP地址和端口找到这个服务对应的IP端口的过程,其实就是服务发现
另一方面,RPC有些不同一般有专门的中间服务来保存服务名和IP信息,比如consul或者etcd,甚至redis如果您想要访问某个服务,请转到这些中间服务来获取IP和端口信息由于dns也是一种服务发现,所以也有基于dns的服务发现组件,比如CoreDNS
可见服务找到了这一块两者有一些区别,但不是很高也不是很低
底部连接形式
连接池
可见两者没有太大区别,所以不是关键。
传输的内容
基于TCP传输的消息,说到底无非就是头和体。
报头用来标记一些特殊的信息,其中最重要的是消息体的长度。
Body是我们真正需要传递的内容,这些内容只能是二进制的01字符串毕竟计算机只知道这些东西所以TCP传输字符串和数字问题不大,因为字符串可以转换成代码再转换成01字符串,数字本身可以直接转换成二进制但是结构,我们得想办法把它转换成二进制的01字符串像json,protobuf等现成的方案有很多
将此结构转换为二进制数组的过程称为序列化,将二进制数组恢复为结构的过程称为反序列化。
序列化和反序列化
我们可以拍张照片,看一看。
可以看到这里的内容有很多冗余,非常啰嗦最明显的是,像头中的信息,事实上,如果我们同意头的数字是内容类型的,我们就不需要每次都真正地传递内容类型字段类似的情况其实在身体的json结构上特别明显
RPC原理
那么问题又来了。
摘要
本质上,RPC不是一个协议,而是一个调用方法,而像gRPC和thrift这样的具体实现就是协议,就是实现RPC调用的协议目的是希望程序员可以像调用本地方法一样调用远程服务方法同时,RPC的实现方式有很多种,不一定基于TCP协议
参考数据