出现动机
建立持久连接
HTTP协议是一种无状态协议,服务器端本身不具有识别客户端的能力,必须借助外部机制,比如session和cookie,才能与特定客户端保持对话。这多多少少带来一些不便,尤其在服务器端与客户端需要持续交换数据的场合(比如网络聊天),更是如此。为了解决这个问题,HTML5提出了浏览器的WebSocket API。
全双工双向通信
SSE对于要从服务器拉取数据的应用来说,已经能够很好的满足要求了。但是对于需要双工通信的应用就不那么适用了,在Web Sockets之前开发人员不得不使用一些折衷方案,例如使用轮询或Comet技术,但是使用这些方案将会给服务器带来很大的压力,会严重增加网络负载。
Web Sockets设计出来的目的就是要取代轮询和 Comet 技术,使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力。
WebSocket协议
在JS中建立了Web Sockets之后,会有一个HTTP请求发送到浏览器以发起连接,在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换到Web Socket协议。也就是说,使用标准的HTTP服务器无法实现Web Sockets,只有支持这种协议的专门服务器才能正常工作。
WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息 Upgrade: WebSocket 表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。首先我们来看一看 Websocket 的握手过程:
Websocket 请求和通常的 HTTP 请求很相似,但是其中有些内容是和 WebSocket 协议密切相关的,相比于普通的 HTTP 请求多了一些字段。
- upgrade:告诉服务器这个HTTP连接是升级的Websocket连接。
- Connection:告知服务器当前请求连接是升级的。
- Sec-WebSocket-Key:为了表示服务器同意和客户端进行Socket连接,服务器端需要使用客户端发送的这个Key进行校验,然后返回一个校验过的字符串给客户端,客户端验证通过后才能正式建立Socket连接。服务器接收请求后,会对请求进行处理,返回的响应头包含了是否同意握手的依据。
- Status Code: 101 Switching Protocols,表示变换协议
- Upgrade 和 Connection:这两个字段是服务器返回的告知客户端同意使用升级并使用Websocket协议,用来完善HTTP升级响应
- Sec-WebSocket-Accept:服务器端将加密处理后的握手Key通过这个字段返回给客户端表示服务器同意握手建立连接。
上述响应头字段被客户端浏览器解析,如果验证到Sec-WebSocket-Accept字段的信息符合要求就会建立连接,同时就可以发送WebSocket的数据帧了。如果该字段不符合要求或者为空或者HTTP状态码不为101,就不会建立连接。
使用
优势与缺陷
优势:
- 能够建立持久的全双工双向通信
- 使用自定义协议,能够在客户端和服务器之间发送非常少量的数据,而不必担心HTTP那样的字节级开销,也因此非常适合移动端。
缺陷(大部分已有应对方法):
- 服务器要支持该协议。但是现在服务器端对于Websocket协议的支持也是不错的,可以选择的库是很丰富的,你可以根据服务器端的语言来选择不同的版本,当然你也可以基于Websocket规范去实现。
- 浏览器不是全面支持。但目前已有库可以解决这个问题。
Socket.io
Socket.io是目前最流行的WebSocket实现,包括服务器和客户端两个部分。它不仅简化了接口,使得操作更容易,而且对于那些不支持WebSocket的浏览器,会自动降为Ajax连接,最大限度地保证了兼容性。它的目标是统一通信机制,使得所有浏览器和移动设备都可以进行实时通信。官方文档
DEMO
代码地址:https://github.com/zjjxj/WebSocket-demo