文章目录
- 有HTTP协议为什么还要RPC
- TCP
- HTTP 和 RPC
- HTTP 和 RPC 有什么区别
- 有HTTP协议为什么还要WebSocket
- 使用HTTP不断轮询
- 长轮询
- WebSocket
- 怎么建立WebSocket连接
有HTTP协议为什么还要RPC
TCP
- TCP三个特点:
面向连接、可靠、基于字节流。
基于字节流
字节流可以理解为一个双向的通道里流淌的数据,这个数据是二进制数据,简单来说就是一大堆 01 串。纯裸 TCP 收发的这些 01 串之间是没有任何边界的,会导致
粘包问题
。因此纯裸的TCP是不能直接拿来用的,你需要在这个基础上加入一些自定义的规则,用于区分消息边界。
于是我们会把每条要发送的数据都包装一下,比如加入消息头,消息头里写清楚一个完整的包长度是多少,根据这个长度可以继续接收数据,截取出来后它们就是我们真正要传输的消息体。
消息头,还可以放各种东西,比如消息体是否被压缩过和消息体格式之类的,只要上下游都约定好了,互相都认就可以了,这就是所谓的协议。
于是基于 TCP,就衍生了非常多的协议,比如 HTTP 和 RPC。
HTTP 和 RPC
- TCP 是传输层的协议,而基于 TCP 造出来的
- HTTP 协议(Hyper Text Transfer Protocol),又叫做超文本传输协议 HTTP 和各类 RPC 协议,它们都只是定义了不同消息格式的应用层协议而已。
- RPC(Remote Procedure Call),又叫做
远程过程调用
。它本身并不是一个具体的协议,而是一种调用方式。
本地方法调用
res = localFunc(req)
该方法在远端服务器上暴露的一个方法,如果我们还能像调用本地方法那样去调用它,这样就可以屏蔽掉一些网络细节
res = remoteFunc(req)
那既然有 RPC 了,为什么还要有 HTTP 呢?
- 电脑上装的各种联网软件,比如 xx管家它们都作为客户端需要跟服务端建立连接收发消息,此时都会用到应用层协议,在这种C/S架构下,它们可以使用自家造的 RPC 协议,因为它只管连自己公司的服务器就 可以了。
- 但浏览器,不仅需要访问自家公司服务器,还要访问其他公司服务器,因此它们需要有个统一的标准,HTTP 就是那个时代用于统一B/S的协议。
- 但现在其实已经没分那么清了,B/S 和 C/S 在慢慢融合。很多软件同时支持多端,比如某度云盘,既要支持网页版,还要支持手机端和 PC 端
HTTP 和 RPC 有什么区别
服务发现
- 向服务器发起请求时,需要知道
IP地址和端口号
,才能建立连接,这个找到服务对应的 IP 端口的过程,其实就是服务发现
。 - 在
HTTP
中,你知道服务的域名,就可以通过DNS 服务
去解析得到它背后的 IP 地址,默认 80 端口。 - 在
RPC
中,会有专门的中间服务
去保存服务名和IP信息,比如Consul 或者 Etcd
,想要访问某个服务,就去这些中间服务去获得 IP 和端口信息
底层连接形式
- HTTP/1.1 协议,其默认在建立底层 TCP 连接之后会一直保持这个连接(Keep Alive),之后的请求和响应都会复用这条连接。(长连接)
- RPC 协议,也是通过建立 TCP 长链接进行数据交互,但是
RPC一般还会建一个连接池
,在请求量大的时候,建立多条连接放在池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用
传输内容(最大区别)
- 基于 TCP 传输的消息,都是
消息头 Header
和消息体 Body
。Header
是用于标记一些特殊信息,其中最重要的是消息体长度。Body
则是放我们真正需要传输的内容,而这些内容只能是二进制 01 串- 但是对于结构体而言,需要通过 Json,Protobuf。把结构体转换为二进制字符串
- 像 Header 里的那些信息,其实如果我们约定好头部的第几位是 Content-Type,就不需要每次都真的把"Content-Type"这个字段都传过来,类似的情况其实在 body 的 Json 结构里也特别明显。
RPC,因为它定制化程度更高,可以采用体积更小的 Protobuf 或其他序列化协议去保存结构体数据,同时也不需要像 HTTP 那样考虑各种浏览器行为,比如 302 重定向跳转啥的。因此性能也会更好一些
有HTTP协议为什么还要WebSocket
- 从 HTTP 协议的角度来看,就是点一下网页上的某个按钮,前端发一次 HTTP请 求,网站返回一次 HTTP 响应。
这种由客户端主动请求,服务器被动响应。
- 玩挂机游戏,就需要
服务器主动发消息给客户端。
使用HTTP不断轮询
网页的前端代码里不断定时发 HTTP 请求到服务器,服务器收到请求后给客户端响应消息。
- 它其实并不是服务器主动发消息到客户端,而是客户端自己不断偷偷请求服务器,只是用户无感知而已。
长轮询
- HTTP 请求发出后,一般会给服务器留一定的时间做响应,比如 3 秒,规定时间内没返回,就认为是超时。
如果我们的 HTTP 请求将超时设置的很大,比如 30 秒,在这 30 秒内只要服务器收到了扫码请求,就立马返回给客户端网页。如果超时,那就立马发起下一次请求。
- 像这种发起一个请求,在较长时间内等待服务器响应的机制,就是所谓的长训轮机制。我们常用的消息队列 RocketMQ 中,消费者去取数据时,也用到了这种方式。
- 本质上还是客户端主动去取数据。
WebSocket
- TCP 连接的两端,同一时间里,双方都可以主动向对方发送数据。这就是所谓的
全双工
。 - HTTP/1.1,也是基于TCP协议的,但是是
半双工
。
- HTTP设计之初,就是考虑网页场景,
客户端发送请求,服务器响应
。根本没想到客户端和服务器都要互相主动发大量数据- 对于网页游戏来说,客户端和服务器需要频繁主动发送数据,于是产生基于TCP的新协议。WebSocket。
怎么建立WebSocket连接
- 一般都是在浏览器上刷的图文,这时候用的是 HTTP 协议,一会打开网页游戏,这时候要切换成WebSocket 协议。
- 于是浏览器在
TCP 三次握手
建立连接之后,都统一使用 HTTP 协议
先进行一次通信。- 如果此时是
普通的 HTTP 请求
,那后续双方就还是老样子继续用普通 HTTP 协议进行交互,这点没啥疑问。 - 如果这时候是
想建立 WebSocket 连接
,就会在 HTTP 请求里带上一些特殊的header 头
- 如果此时是
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
- 浏览器想升级协议(Connection: Upgrade),并且想升级成 WebSocket 协议(Upgrade: WebSocket)。同时带上一段随机生成的 base64 码(Sec-WebSocket-Key),发给服务器。
- 如果服务器正好支持升级成 WebSocket 协议。就会走 WebSocket 握手流程,同时根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串,放在 HTTP 响应的 Sec-WebSocket-Accept 头里,同时带上101状态码,发回给浏览器。
- 浏览器也用同样的公开算法将base64码转成另一段字符串,如果这段字符串跟服务器传回来的字符串一致,那验证通过。
HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n
Upgrade: WebSocket\r\n
Connection: Upgrade\r\n