论WebSocket
为什么有HTTP还要有WebSocket?
当我们访问某个网页时,点击一下按钮,页面立即跳转。从HTTP的角度来看,就是前端发一次HTTP请求,网站返回一次HTTP响应。
这种由客户端主动请求,服务器响应的方式,能满足大部分网页的功能场景。
但是在这种模式下,服务器从来就不会主动给客户端发一次消息。假如有以下场景:你在哔哩哔哩网页端刷动态视频,然后页面突然提示你有新动态(或新消息)。
这种情况应该如何实现呢?
其实,问题的痛点在于,怎么样才能在用户不做任何操作的情况下,网页能收到消息并发生变更。
思路一,轮询
最简单的办法是,在网页的前端代码里,不断定时发HTTP请求到服务器(喂喂喂,有新消息吗),服务器收到请求后给客户端响应消息(有的有的)。
这是一种伪服务器推的形式,它并不是服务器主动发消息,而是客户端偷偷请求服务器,只是用户无感知而已
听起来这是一种很low的方式,但它实现简单,也有应用场景。比如某信平台的扫码登录,当二维码出现后,前端网页不知道用户扫没扫,于是不断向后端服务器询问,看有没有人扫过这个码,而且是以1到2秒的间隔不断发出请求,这样可以保证用户在扫后,能在1到2秒内得到及时的反馈。
缺点:用户会有1到2秒的卡顿,且大量的轮询会增加服务器的负担
思路二,长轮询
长轮询是对轮询的改进。我们知道,客户端给服务器发出HTTP请求后,会给服务器留一定的时间做响应(比如3s)。如果我们将 超时时间设置很长(30s),服务器就可以在30内等待是否有新消息,有则立即返回。超时后客户端发起下一次请求。某度云网盘的扫码登陆就是这么干的。
这样一来,减少了轮询次数,扫码后也能及时反馈
以上两种解决方案的本质还是客户端去主动取数据,如果有大量数据需要从服务器推送到客户端呢?
思路三,WebSocket
WebSocket和Socket并无依赖关系,所属层级,实现方式都不一样,但都能实现全双工通信
我们知道,HTTP协议是基于TCP协议的。TCP是全双工协议,支持客户端和服务器同时给对方发送数据。而HTTP1.x是半双工协议,同一时间里,客户端和服务端只能有一方发送数据。所以,我们需要新的全双工协议,WebSocket协议。
浏览器在TCP三次握手建立连接后,都先使用HTTP进行一次通信。
-
如果后续想建立普通的HTTP连接,那么这次的HTTP请求就是普通的HTTP请求。
-
如果后续想建立websocket连接,那么这次的HTTP请求会带上一些特殊的header头。
Cinnection: Upgrade 表示客户端想升级协议。
Upgrade: websocket 表示客户端想升级成websocket协议。
Sec-WebSocket-Ket: T2a6wZlAwhgQNqruZ2YUyg 一段随机生成的BASE64码
如果服务器正好支持WebSocket协议,就会走WebSocket握手流程。服务器会将客户端发来的BASE64码通过某公开算法变成另一端字符串放在Sec-WebSocket-Accep里,然后带上101状态码(协议切换)发回给客户端
HTTP/1.1101 Switching Protocols
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=
Upgrade: websocket
Connection: Upgrade
随后,浏览器通过同一公开算法将BASE64码转成新字符串,并与服务器发来的字符串进行匹配,匹配成功则验证通过。
websocket数据帧的格式
websocket数据帧的格式和RPC协议,HTTP协议一样,同样是消息头+消息体的形式,解决了裸TCP协议的粘包问题