WebSocket是一种比较新的协议,它是伴随着html5
规范而生的,虽然还比较年轻,但大多主流浏览器都已经支持。它使用方面、应用普遍,已经渗透到先后端开发的各类场景中。javascript
对http一问一答
中二式流程的不满,催生了支持双向通讯的WebSocket
诞生。WebSocket是个不太干净
协议。html
不是。目前此协议的受众的也不只仅是web开发者。html5
WebSocket只是一种协议,它和http协议同样,使用相似okhttp
的组件,能够在任何地方进行调用,甚至能够借助WebSocket实现RPC
框架。java
WebSocket和http同样,都是处于OSI
模型中的最高层:应用层
。nginx
http
协议进行握手,握手成功后,就会变身为
TCP通道
,今后与http再也不相见。
使用netstat或者ss,可以看到对应的链接,它与处于抽象层的socket,在外观上没有区别。web
长轮询,就是客户端发送一个请求,服务端将一直在这个链接上等待(固然有一个超长的超时时间),直到有数据才返回,它依然是一个一问一答的模式。好比著名的comted。chrome
WebSocket在握手成功后,就是全双工
的TCP通道,数据能够主动从服务端发送到客户端,处于连接两端的应用没有任何区别。编程
WebSocket建立的链接和Http的长链接是不同的。因为Http长链接底层依然是Http协议,因此它仍是一问一答,只是Hold住了一条命长点的链接而已。后端
长轮询和Http长链接是阻塞的I/O,但WebSocket能够是非阻塞的(具体是多路复用)。浏览器
WebSocket的链接建立是借助Http协议进行的。这样设计主要是考虑兼容性,在浏览器中就能够很方便的发起请求,看起来比较具备迷惑性。
下图是一个典型的由浏览器发起的ws请求,能够看到和http请求长的是很是类似的。可是,它只是请求阶段长得像而已:
ws://\*\*\*
,或者是使用了SSL/TLS加密的安全协议
wss:
,用来标识是WebSocket请求。
一、 首先,经过Http头里面的Upgrade
域,请求进行协议转换。若是服务端支持的话,就能够切换到WebSocket协议。简单点讲:链接已经在那了,经过握手切换成ws协议,就是切换了链接的一个状态而已。
一、Connection
域能够认为是与Upgrade
域配对的头信息。像nginx等代理服务器,是要先处理Connection,而后再发起协议转换的。
Sec-WebSocket-Key 是随机的字符串,服务器端会用这些数据来构造出一个 SHA-1 的信息摘要。如此操做,能够尽可能避免普通 HTTP 请求被误认为 WebSocket 协议。
其余的,像Sec-WebSocket*字样的头信息,代表了客户端支持的子协议以及其余信息。像loT中很流行的mqtt,就能够做为WebSocket的子协议。
<script>
var ws = new WebSocket('ws://localhost:80'); ws.onopen = function () { console.log('ws onopen'); ws.send('from client: hello'); }; ws.onmessage = function (e) { console.log('ws onmessage'); console.log('from server: ' + e.data); }; ... </script> 复制代码
WebSocket是经过事件通知的方式运行的。它包含四个事件和两个动做(发送和关闭)。
WebSocket的事件
事件 | 钩子 | 备注 |
---|---|---|
open | onopen | 链接创建时触发 |
message | onmessage | 客户端接收服务端数据时触发 |
error | onerror | 通讯发生错误时触发 |
close | onclose | 链接关闭时触发 |
数据可直接经过Socket.send()
方法进行传输。
经过chrome的Inspect->Network->WS,能够看到页面上的WebSocket链接。如图Opcode为2,代表它是一个二进制帧。
参考:(tools.ietf.org/html/rfc645…)
心跳对应的ping、pong操做,opcode分别是0x九、0xA。收到心跳的一方须要自行更新心跳的更新时间。同使用Netty,咱们到底在开发些什么?介绍的相似,在一些移动环境中,须要更加智能的控制心跳。
nginx官网已经给出了例子。主要是Upgrade和Connection头的设置。
map $http_upgrade $connection_upgrade { default upgrade; '' close; } location /chat/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } 复制代码
须要注意的是,nginx作负载均衡,不须要配置ip_hash
等参数,nginx自然支持。因为ip_hash仅使用ip地址的前三个数字作hash,还有可能形成服务端的不均衡。
能够实现javax.WebSocket下的包,简单的实现ws服务端。目前基本能够经过注解的方式去编写代码,好比ServerEndpoint
。
推荐使用基于netty的netty-socketio进行服务端的编写。因为使用的是netty,因此可以在多个层面进行切入,获取一些统计数据,执行一些控制指令。socketio是一套解决方案,它有多个语言的客户端,并处理了市面上大多数的兼容问题。
保持一个长链接,当服务端游新的消息,可以实时的推送到使用方。像知乎的点赞通知、评论等,均可以使用WebSocket通讯。
某些使用H5
的客户端,为了简化开发,也会使用WebSocket进行消息的通知,因为它是实时推送的,会有更好的用户体验。
一些次优级别的数据,好比行为日志、trace、异常执栈收集等,均可以开辟专门的WebSocket通道进行传输。这可以增长信息的集中度,并能及时的针对用户的行为进行合适的配置推送。因为大多数浏览器内核都支持,它将使客户端APM
编程模型变得简单。
虽然使用Fiddler、Charles等可以抓到不少WebSocket包。但若是同时开启SSL,传输加密后的二进制数据,会大幅增长破解的成本,会安全的多。
这个...因为是双工长链接,服务端彻底能够推送一些钩子命令,甚至直接是代码,在客户端进行执行。好比截个屏,录个音,种个小马。用户只要经过了受权申请,剩下的就随你发挥了。
支付宝偷偷调用你的相机给你拍照的梗,我是相信的。