什么是websocket
WebSocket是HTML5新增的协议,它的目的是在浏览器和服务器之间建立一个不受限的双向通信的通道,使服务器和客户端可以实时高效的通信。同时服务器可以在任意时刻主动发送消息给客户端-浏览器。
为什么会出现 websoket?
为什么传统的HTTP协议不能做到WebSocket实现的功能?
我们都知道HTTP 协议,在 HTTP1.0
中,一次req 请求对应一个 res,然后这次HTTP请求就结束了。
在HTTP1.1中进行了改进,增加了keep-alive,可以对一个请求可以进行重用,可以进行多次Request和Response。但是HTTP协议中永远是一个request对应一个response。而且这个response也是被动的,不能主动发起。
这样一来,要在浏览器中搞一个实时聊天,在线炒股(不鼓励),或者在线多人游戏的话就没法实现了,只能借助Flash插件,轮询,长连接。
轮询是指浏览器通过JavaScript启动一个定时器,然后以固定的间隔给服务器发请求,询问服务器有没有新消息。这个机制的缺点一是实时性不够,二是频繁的请求会给服务器带来极大的压力。
Comet本质上也是轮询,但是在没有消息的情况下,服务器先拖一段时间,等到有消息了再回复。这个机制暂时地解决了实时性问题,但是它带来了新的问题:以多线程模式运行的服务器会让大部分线程大部分时间都处于挂起状态,极大地浪费服务器资源。另外,一个HTTP连接在长时间没有数据传输的情况下,链路上的任何一个网关都可能关闭这个连接,而网关是我们不可控的,这就要求Comet连接必须定期发一些ping数据表示连接“正常工作”。
以上两种机制都治标不治本,所以,HTML5推出了WebSocket标准,让浏览器和服务器之间可以建立无限制的全双工通信,任何一方都可以主动发消息给对方。
在说下 HTTP是应用层协议,是建立在TCP协议之上的,TCP协议属于传输层协议,本身就是可靠的,全双工通信协议,HTTP协议的请求-应答机制限制了全双工通信。当WebSocket连接建立以后,其实只是简单规定了一下:说哥们,接下来,咱们通信就不使用HTTP那套了,咱们尽量保持链接,随便互相发数据吧。
握手机制:
WebSocket并不是全新的协议,而是利用了HTTP协议来建立连接。
浏览器和服务器只需要做一次握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
具体的握手过程就不说了,会涉及到代码,没办法说明。有兴趣的可以看下 mdn 上 了解下。
我们来看看WebSocket连接是如何创建的。
首先,WebSocket连接必须由浏览器发起,因为请求协议是一个标准的HTTP请求,格式如下:
GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13
该请求和普通的HTTP请求有几点不同:
- GET请求的地址不是类似
/path/
,而是以ws://
开头的地址; - 请求头
Upgrade: websocket
和Connection: Upgrade
表示这个连接将要被转换为WebSocket连接; Sec-WebSocket-Key
是用于标识这个连接,并非用于加密数据;Sec-WebSocket-Version
指定了WebSocket的协议版本。
随后,服务器如果接受该请求,就会返回如下响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string
该响应代码101
表示本次连接的HTTP协议即将被更改,更改后的协议就是Upgrade: websocket
指定的WebSocket协议。
版本号和子协议规定了双方能理解的数据格式,以及是否支持压缩等等。如果仅使用WebSocket的API,就不需要关心这些。
现在,一个WebSocket连接就建立成功,浏览器和服务器就可以随时主动发送消息给对方。消息有两种,一种是文本,一种是二进制数据。通常,我们可以发送JSON格式的文本,这样,在浏览器处理起来就十分容易。
为什么WebSocket连接可以实现全双工通信而HTTP连接不行呢?实际上 dddd 安全的WebSocket连接机制和HTTPS类似。首先,浏览器用wss://xxx
创建WebSocket连接时,会先通过HTTPS创建安全的连接,然后,该HTTPS连接升级为WebSocket连接,底层通信走的仍然是安全的SSL/TLS协议。
浏览器支持情况
很显然,要支持WebSocket通信,浏览器得支持这个协议,这样才能发出ws://xxx
的请求。目前,支持WebSocket的主流浏览器如下:
- Chrome
- Firefox
- IE >= 10
- Sarafi >= 6
- Android >= 4.4
- iOS >= 8
服务器:
由于WebSocket是一个协议,服务器具体怎么实现,取决于所用编程语言和框架本身。Node.js本身支持的协议包括TCP协议和HTTP协议,要支持WebSocket协议,需要对Node.js提供的HTTPServer做额外的开发。已经有若干基于Node.js的稳定可靠的WebSocket实现,我们直接用npm安装使用即可。
node 里 比如 有 ws,socket.io 模块,npm 装就可以.
使用相关
Websocket 使用 ws 或 wss 的统一资源标志符,类似于 HTTPS,其中 wss 表示在 TLS 之上的 Websocket。如:
ws://example.com/wsapi wss://secure.example.com/
Websocket 使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Websocket 协议使用 80 端口;运行在 TLS 之上时,默认使用 443 端口。
如何使用
可以参考 mdn 的 api 文档即可
总结:
websocket 就是一个基于 http 的一个增强的协议,既然是协议 浏览器和服务器都需要支持了这个协议才能提供我们使用。在这个基础上我们只需要使用已提供的 api 即可实现我们的需求。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
参考资料 https://www.liaoxuefeng.com/wiki/1022910821149312/1103303693824096
我写的 demo:
使用 websocket 做了一个热更新 demo,有兴趣可以看下