WebSocket
简介
伴随着HTML5出现的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,任何一方都可以主动发消息给对方
相关面试题
- 简述一下 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 连接直接发送和接收消息。
- WebSocket 相比于传统的 HTTP 有什么优势
HTTP
协议中,响应必须在请求之后发生,服务器是被动的,无法主动推送消息。而让客户端不断的发起请求又白白的占用了资源WebSocket
利用 HTTP
协议完成握手之后,就可以与服务器建立持久的连接,服务器可以在任何需要的时候,主动推送消息给客户端,这样占用的资源最少,同时实时性也最高。
- 前端实现即时通讯的方式有哪些?
- 短轮询。即客户端每隔一段时间就向服务器发送消息,询问有没有新的数据
- 长轮询,发起一次请求询问服务器,服务器可以将该请求挂起,等到有新消息时再进行响应。响应后,客户端立即又发起一次请求,重复整个流程。
- 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
有一些预定义的事件名,比如message
、connect
等。为了避免冲突,建议自定义事件名使用一个特殊的前缀,比如$
除此之外,Socket.io
对低版本浏览器还进行了兼容处理,如果浏览器不支持WebSocket,Socket.io
将使用长轮询处理