WebSocket是什么
WebSocket, 即 Web 浏览器与 Web 服务器之间全双工通信标准,是一种基于 TCP 的轻量级网络通信协议,在地位上是与 HTTP“平级”的。
WebSocket作为一个协议,与HTTP协议、FTP协议、DNS服务同属于应用层,是TCP/IP协议族下的一个子集,同HTTP协议一样,WebSocket也是基于TCP协议基础上实现的。
通俗讲:使用WebSocket做为通讯协议时,客户端可以发送消息给服务端,同时,服务端也可以发送消息给客户端。
如果你要说,两台服务器不是也可以这样发送相互发送消息?接着往下看~
为什么要有 WebSocket
HTTP属于“请求 - 应答”是一种“半双工”的通信模式,虽然可以双向收发数据,但同一时刻只能一个方向上有动作,传输效率低。更关键的一点,它是一种“被动”通信模式,服务器只能“被动”响应客户端的请求,无法主动向客户端发送数据。
若是是浏览器做为客户端,而只能单向的由浏览器不算的“询问”服务器了。
那么,“请求 - 应答”有什么不好的地方呢?
虽然后来的 HTTP/2、HTTP/3 新增了 Stream、Server Push 等特性,但“请求 - 应答”依然是主要的工作方式。这就导致 HTTP 难以应用在动态页面、即时消息、网络游戏等要求“实时通信”的领域。
在 WebSocket 出现之前,在浏览器环境里用 JavaScript 开发实时 Web 应用很麻烦。因为浏览器是一个“受限的沙盒”,不能用 TCP,只有 HTTP 协议可用,所以就出现了很多“变通”的技术,“轮询”(polling)就是比较常用的的一种。
简单地说,轮询就是不停地向服务器发送 HTTP 请求,问有没有数据,有数据的话服务器就用响应报文回应。如果轮询的频率比较高,那么就可以近似地实现“实时通信”的效果。
但轮询的缺点也很明显,反复发送无效查询请求耗费了大量的带宽和 CPU 资源,非常不经济。
所以,为了克服 HTTP“请求 - 应答”模式的缺点,WebSocket 就“应运而生”了。它原来是 HTML5 的一部分,后来“自立门户”,形成了一个单独的标准。
WebSocket 的特点
WebSocket 是一个真正“全双工”的通信协议,与 TCP 一样,客户端和服务器都可以随时向对方发送数据,而不用像 HTTP“你拍一,我拍一”那么“客套”。于是,服务器就可以变得更加“主动”了。一旦后台有新的数据,就可以立即“推送”给客户端,不需要客户端轮询,“实时通信”的效率也就提高了。
服务发现方面,WebSocket 没有使用 TCP 的“IP 地址 + 端口号”,而是延用了 HTTP 的 URI 格式,但开头的协议名不是“http”,引入的是两个新的名字:“ws”和“wss”,分别表示明文和加密的 WebSocket 协议。
WebSocket 的默认端口也选择了 80(ws) 和 443(wss),因为现在互联网上的防火墙屏蔽了绝大多数的端口,只对 HTTP 的 80、443 端口“放行”,所以 WebSocket 就可以“伪装”成 HTTP 协议,比较容易地“穿透”防火墙,与服务器建立连接。具体是怎么“伪装”的,我稍后再讲。
WebSocket的控制帧
WebSocket控制帧有3种:Close、Ping以及Pong。控制帧的Opcode操作码定义为0x08(关闭帧)、0x09(Ping帧)、0x0A(Pong帧)。
Close帧很容易理解:客户端如果接收到关闭帧,就关闭连接;当然,客户端也可以发送关闭帧给服务端,服务端收到该帧之后也会关闭连接。
Ping和Pong是WebSocket的心跳帧,用来保证客户端维持正常在线状态。WebSocket为了保持客户端、服务端的实时双向通信,需要确保客户端、服务端之间的TCP通道保持连接没有断开。
然而,如果长时间没有数据往来的连接,依旧保持着双向连接,就可能会浪费服务端的连接资源,所以需要关闭这些长时间空闲的连接。
有一些场景需要保持那些长时间空闲的连接,这时可以采用Ping和Pong两个心跳帧来完成。一般来说,服务端给客户端发送Ping,然后客户端发送Pong来回应,表明自己仍然在线。
WebSocket 的握手
和 TCP、TLS 一样,WebSocket 也要有一个握手过程,然后才能正式收发数据。
这里它还是搭上了 HTTP 的“便车”,利用了 HTTP 本身的“协议升级”特性,“伪装”成 HTTP,这样就能绕过浏览器沙盒、网络防火墙等等限制,这也是 WebSocket 与 HTTP 的另一个重要关联点。
WebSocket 的握手是一个标准的 HTTP GET 请求,但要带上两个协议升级的专用头字段:
- “Connection: Upgrade”,表示告诉服务器要求协议“升级”;
- “Upgrade: websocket”,表示要“升级”成 WebSocket 协议。
另外,为了防止普通的 HTTP 消息被“意外”识别成 WebSocket,握手消息还增加了两个额外的认证用头字段(所谓的“挑战”,Challenge):
- Sec-WebSocket-Key:一个 Base64 编码的 16 字节随机数,作为简单的认证密钥;
- Sec-WebSocket-Version:协议的版本号,当前必须是 13,也就是目前最新的协议版本号。
WebSocket通信过程
抓包
浏览器F12 > Network > ws
注意,只会有一个通讯不中断时,只会有一条请求URL的记录,清除记录下次通讯也会看不到的,更新的通讯数据再Data展示,如下图。
参考
1、时间极客 - 透视HTTP协议丨WebSocket:沙盒里的TCP
3、《图解HTTP》
4、B站搜索了解~