-
使用HTTP不断的轮询
-
痛点在于,怎么样才能在用户不做任何操作的情况下,网页能收到消息并发生变更。
-
常用的解决方案是,网页的前端代码里不断定时发 HTTP 请求到服务器,服务器收到请求后给客户端响应消息。「伪」服务器推的形式。
-
场景也有很多,最常见的就是扫码登录。
-
某信公众号平台,登录页面二维码出现之后,前端网页根本不知道用户扫没扫,于是不断去向后端服务器询问,看有没有人扫过这个码。而且是以大概 1 到 2 秒的间隔去不断发出请求,这样可以保证用户在扫码后能在 1 到 2 秒内得到及时的反馈,不至于等太久。
-
-
-
用HTTP定时轮询两个比较明显的问题:
-
当你打开 F12 页面时,你会发现满屏的 HTTP 请求。虽然很小,但这其实也消耗带宽,同时也会增加下游服务器的负担。
-
最坏情况下,用户在扫码后,需要等个 1~2 秒,正好才触发下一次 HTTP 请求,然后才跳转页面,用户会感到明显的卡顿。
-
-
-
长轮询
-
HTTP 请求发出后,一般会给服务器留一定的时间做响应,比如 3 秒,规定时间内没返回,就认为是超时。
-
如果我们的 HTTP 请求将超时设置的很大,比如 30 秒,在这 30 秒内只要服务器收到了扫码请求,就立马返回给客户端网页。如果超时,那就立马发起下一次请求。
-
在较长时间内等待服务器响应的机制,就是所谓的长训轮机制。我们常用的消息队列 RocketMQ 中,消费者去取数据时,也用到了这种方式。
-
在用户不感知的情况下,服务器将数据推送给浏览器的技术,就是所谓的服务器推送技术,它还有个毫不沾边的英文名,comet 技术
-
两种方式本质上,其实还是客户端主动去取数据。
-
-
websocket是什么
-
TCP 连接的两端,同一时间里,双方都可以主动向对方发送数据。这就是所谓的全双工。
-
最广泛的
HTTP/1.1
,也是基于TCP协议的,同一时间里,客户端和服务器只能有一方主动发数据,这就是所谓的半双工。 -
怎么建立websocket连接
-
一般都是在浏览器上刷的,这时候用的是 HTTP 协议
-
一会打开网页游戏,这时候就得切换成我们新介绍的 WebSocket 协议
-
浏览器在 TCP 三次握手建立连接之后,都统一使用 HTTP 协议先进行一次通信。
-
如果此时是普通的 HTTP 请求,那后续双方就还是老样子继续用普通 HTTP 协议进行交互。
-
如果这时候是想建立 WebSocket 连接,就会在 HTTP 请求里带上一些特殊的header 头
-
header 头的意思是,浏览器想升级协议(Connection: Upgrade),并且想升级成 WebSocket 协议(Upgrade: WebSocket)。同时带上一段随机生成的 base64 码(Sec-WebSocket-Key),发给服务器。
-
如果服务器正好支持升级成 WebSocket 协议。就会走 WebSocket 握手流程,同时根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串,放在 HTTP 响应的
Sec-WebSocket-Accept
头里,同时带上101状态码
,发回给浏览器。响应如下 -
101 确实不常见,它其实是指协议切换。
-
浏览器也用同样的公开算法将
base64码
转成另一段字符串,如果这段字符串跟服务器传回来的字符串一致,那验证通过。 -
就这样经历了一来一回两次 HTTP 握手,WebSocket就建立完成了,后续双方就可以使用 webscoket 的数据格式进行通信了。
-
-
-
-
websocket抓包
-
经历了三次TCP握手之后,利用 HTTP 协议升级为 WebSocket 协议。
-
WebSocket只有在建立连接时才用到了HTTP,升级完成之后就跟HTTP没有任何关系了。
-
-
websocket的消息格式
-
数据包在WebSocket中被叫做帧
-
opcode字段:这个是用来标志这是个什么类型的数据帧
-
等于 1 ,是指text类型(
string
)的数据包 -
等于 2 ,是二进制数据类型(
[]byte
)的数据包 -
等于 8 ,是关闭连接的信号
-
-
payload字段:存放的是我们真正想要传输的数据的长度,单位是字节。
-
什么情况下应该读 7 bit,什么情况下应该读7+16bit呢?
-
WebSocket会用最开始的7bit做标志位。不管接下来的数据有多大,都先读最先的7个bit,根据它的取值决定还要不要再读个 16bit 或 64bit。
-
如果
最开始的7bit
的值是 0~125,那么它就表示了 payload 全部长度,只读最开始的7个bit
就完事了。 -
如果是
126(0x7E)
。那它表示payload的长度范围在126~65535
之间,接下来还需要再读16bit。这16bit会包含payload的真实长度。 -
如果是
127(0x7F)
。那它表示payload的长度范围=65536
,接下来还需要再读64bit。这64bit会包含payload的长度。这能放2的64次方byte的数据,换算一下好多个TB,肯定够用了。
-
-
payload data字段:这里存放的就是真正要传输的数据,在知道了上面的payload长度后,就可以根据这个值去截取对应的数据。
-
WebSocket的数据格式也是数据头(内含payload长度) + payload data 的形式。
-
因为 TCP 协议本身就是全双工,但直接使用纯裸TCP去传输数据,会有粘包的"问题"。为了解决这个问题,上层协议一般会用消息头+消息体的格式去重新包装要发的数据。
-
而消息头里一般含有消息体的长度,通过这个长度可以去截取真正的消息体。
-
-
-
websocket使用的场景
-
WebSocket完美继承了 TCP 协议的全双工能力,并且还贴心的提供了解决粘包的方案。
-
适用于需要服务器和客户端(浏览器)频繁交互的大部分场景
-
比如网页/小程序游戏,网页聊天室,以及一些类似飞书这样的网页协同办公软件。
-
在使用 WebSocket 协议的网页游戏里,怪物移动以及攻击玩家的行为是服务器逻辑产生的,对玩家产生的伤害等数据,都需要由服务器主动发送给客户端,客户端获得数据后展示对应的效果。
-
-
-