> 技术文档 > WebSocket

WebSocket


简介

伴随着HTML5出现的WebSocket,从协议上赋予了服务器主动推送消息的能力

WebSocket

从上图可以看出:

  • WebSocket 也是建立在TCP协议之上的,利用的是TCP全双工通信的能力
  • 使用 WebSocket 会经历两个阶段:握手阶段、通信阶段

虽然优于轮询方案,但是 WebSocket 也是有缺点的:

  • 兼容性

    WebSocket是HTML5新增的内容,因此古董版本的浏览器并不支持

  • 维持TCP连接需要耗费资源

    对于那些消息量少的场景,维持TCP连接确实会造成资源的浪费

    为了充分利用TCP连接的资源,在使用了WebSocket的页面可以放弃ajax,都用WebSocket进行通信,当然这会带来程序设计上的一些问题,需要权衡。

握手

当客户端需要和服务器使用WebSocket进行通信时,首先会使用 HTTP 协议完成一次特殊的请求-响应,这一次请求-响应就是WebSocket握手

在握手阶段,首先由客户端向服务器发送一个请求,请求地址格式如下:

# 使用HTTPws://mysite.com/path# 使用HTTPSwss://mysite.com/path

请求头如下:

Connection: Upgrade /* 表示本次请求是要升级协议 */Upgrade: websocket /* 后续的协议升级为websocket */Sec-WebSocket-Version: 13 /* websocket协议版本 */Sec-WebSocket-Key: YWJzZmFkZmFzZmRhYw==

服务器如果同意,就应该响应下面的消息

HTTP/1.1 101 Switching Protocols /* 更换协议 */Connection: Upgrade /* 协议升级 */Upgrade: websocket /* 升级到 websocket */Sec-WebSocket-Accept: ZzIzMzQ1Z2V3NDUyMzIzNGVy

握手完成,后续消息收发不再使用HTTP,任何一方都可以主动发消息给对方


相关面试题

  1. 简述一下 WebSocket 协议

WebSocket 协议是 HTML5 的新协议,相对于 HTTP,它是一个持久连接的协议,利用 HTTP 协议完成握手,然后通过 TCP 连接通道发送消息,使用 WebSocket 协议可以实现服务器主动推送消息。
客户端若要发起 WebSocket 连接,首先必须向服务器发送 HTTP 请求以完成握手,请求行中的 path 需要使用ws:开头的地址,请求头中要分别加入upgrade、connection、Sec-WebSocket-Key、Sec-WebSocket-Version标记

然后,服务器收到请求后,发现这是一个 WebSocket 协议的握手请求,于是响应行中包含Switching Protocols,同时响应头中包含upgrade、connection、Sec-WebSocket-Accept标记
当客户端收到响应后即可完成握手,随后使用建立的 TCP 连接直接发送和接收消息。


  1. WebSocket 相比于传统的 HTTP 有什么优势

HTTP 协议中,响应必须在请求之后发生,服务器是被动的,无法主动推送消息。而让客户端不断的发起请求又白白的占用了资源
WebSocket 利用 HTTP 协议完成握手之后,就可以与服务器建立持久的连接,服务器可以在任何需要的时候,主动推送消息给客户端,这样占用的资源最少,同时实时性也最高。


  1. 前端实现即时通讯的方式有哪些?
  • 短轮询。即客户端每隔一段时间就向服务器发送消息,询问有没有新的数据
  • 长轮询,发起一次请求询问服务器,服务器可以将该请求挂起,等到有新消息时再进行响应。响应后,客户端立即又发起一次请求,重复整个流程。
  • WebSocket,握手完毕后会建立持久性的连接通道,随后服务器可以在任何时候推送新消息给客户端

WebSocket API

const ws = new WebSocket(\"地址\"); // 创建websocket连接,浏览器自动握手// 事件:握手完成后触发ws.onopen = function () { console.log(\'连接到了服务器\');};// 事件:收到服务器消息后触发ws.onmessage = function (e) { console.log(e.data); // e.data:服务器发送的消息};// 事件:连接关闭后触发ws.onclose = function () { console.log(\'连接关闭了\');};// 发送消息到服务器ws.send(消息);// 连接状态:0-正在连接中 1-已连接 2-正在关闭中 3-已关闭ws.readyState

Socket.io

原生的接口虽然简单,但是会有一些问题,由于连接双方可以在任何时候发送任何类型的数据,所以另一方必须清楚这个数据的含义是什么
Socket.io 帮助我们解决了这些问题,它把消息放到不同的事件中,通过监听和触发事件来实现对不同消息的处理
客户端和服务器双方事先约定好不同的事件,事件由谁监听,由谁触发,就可以把各种消息进行有序管理了

注意,Socket.io为了实现这些要求,对消息格式进行了特殊处理,因此如果一方要使用Socket.io,双方必须都使用

在约定事件名时要注意,Socket.io 有一些预定义的事件名,比如messageconnect等。为了避免冲突,建议自定义事件名使用一个特殊的前缀,比如$
除此之外,Socket.io对低版本浏览器还进行了兼容处理,如果浏览器不支持WebSocket,Socket.io将使用长轮询处理