websocket 不同于其他的HTTP协议,他是独立于HTTP存在的另外一种通信协议。比如,像这样的一个路径 ws://websocket.example.com/ ,就是一个websocket 通信. 通常的实时通信并不会传输大量的内容, 所以,对于HTTP协议那种,进行连接时需要传递,cookie和request Headers来说, 这种方式的通信协议,会造成一定的时延(latency). websocket通信协议就是在这样的背景下诞生了, 他与SSE,ajax polling不同的是--双向通信.
talk is cheap, show the code
我们来看一个简单的websocket demo
var socket = new WebSocket('ws://localhost:8080/'); socket.onopen = function () { console.log('Connected!'); }; socket.onmessage = function (event) { console.log('Received data: ' + event.data); socket.close(); }; socket.onclose = function () { console.log('Lost connection!'); }; socket.onerror = function () { console.log('Error!'); }; socket.send('hello, world!');可以说上面就是一个健全的websocket 通信了. 和SSE一样,我们需要创建一个WebSocket对象, 里面的参数指定连接的路由. 而且,他也是事件驱动的.常见的事件监听有.
event effect
open 当ws连接建立时触发
message 当有信息到来时触发
error 当连接发生错误时触发
close 当连接断开时触发
websocket 发送数据
另外,websocket 最大的特点就是可以双向通信。这里可以使用.
ws.send() 方法发送数据, 不过只能发送String和二进制. 这里,我们通常call 数据叫做 Frames . 他是数据发送的最小单元.包含数据的长度和数据内容.
下面就是几种常用的发送方式
socket.send("Hello server!"); socket.send(JSON.stringify({'msg': 'payload'})); var buffer = new ArrayBuffer(128); socket.send(buffer); var intview = new Uint32Array(buffer); socket.send(intview); var blob = new Blob([buffer]); socket.send(blob);
另外还可以使用 binaryType 指定传输的数据格式,不过一般都用不上,就不说了.
不过需要提醒的是, send方法,一般在open和message的回调函数中调用.
websocket 接受数据同理,和SSE差不多, 通过监听message事件,来接受server发送回来的数据. 接受其实就是通过 event.data 来获取. 不过, 需要和server端商量好data的类型.
ws.onmessage = function(msg) { if(msg.data instanceof Blob) { processBlob(msg.data); } else { processText(JSON.parse(msg.data)); //接受JSON数据 } }
那server端应该怎样处理websocket通信呢?
websocket虽然是另外一种协议,不过底层还是封装了TCP通信, 所以使用nodeJS的net模块,基本就可以满足,不过里面需要设置很多的头. 这里推荐使用 ws 模块.
NodeJS 发送websocket数据简单的websocket demo
var WebSocketServer = require('ws').Server , wss = new WebSocketServer({ port: 8080 }); //通过ws+ssl的方式通信. 和HTTPS类似 wss.on('connection', function connection(ws) { ws.on('message', function incoming(message) { console.log('received: %s', message); }); ws.send('something'); });可以参考treeHouse 编写的 WSdemo
为什么websocket会有子协议由于websocket 本身的协议对于数据格式来说,不是特别的清晰明了,ws可以传输text,blob,binary等等其他格式. 这样对于安全性和开发性能来说,友好度很低。所以,为了解决这个问题, subprotocols 出现了. 在使用时,client和server都需要配置一样的subprotocols. 例如:
var ws = new WebSocket('wss://example.com/socket', ['appProtocol', 'appProtocol-v2']);服务端需要将subprotocols发送过去, 在handshakes的过程中,server 会识别subprotocols. 如果,server端也有相同的子协议存在, 那么连接成功. 如果不存在则会触发error, 连接就被断开了.
websocket 协议内容
websocket 是有HyBi Working Group 提议并创建的。 主要的内容就是 一张表.
相比TCP来说, 真的是简单~
其实一句话就可以说完.
Figure 17-1. WebSocket frame: 2–14 bytes + payload
具体内容是:
第一个比特(FIN) 表明, 该frame 是否信息的最后一个. 因为信息可以分多个frame包传送. 但最终客户端接收的是整个数据
opcode(4bit)--操作码, 表示传送frame的类型 比如text(1)|| binary(2)
Mask 比特位表示该数据是否是从 client => server.
Extended length 用来表示payload 的长度
Masking key 用来加密有效值
Payload 就是传输的数据
首先,答案是。 但,网上有两部分内容:
WebSocket is subject to the same-origin policyWebSocket is not subject to the same-origin policy
看到这里我也是醉了. 事实上websocket 是可以跨域的。 但是为了安全起见, 我们通常利用CORS 进行 域名保护.
即,设置如下的相应头:
Access-Control-Allow-Origin:这时, 只有 能够进行跨域请求. 其他的都会deny.
那什么是CORS呢?
how does CORS work
CORS 是Cross-Origin Resource Sharing--跨域资源分享. CORS 是W3C 规范中 一项很重要的spec. 一开始,ajax 收到 the same origin policy 的限制 奈何不得。 结果出来了JSONP 等 阿猫阿狗. 这让ajax很不安呀~ 但是,W3C 大手一挥, 亲, 我给你开个buff. 结果CORS 就出来了。
CORS 就是用来帮助AJAX 进行跨域的。 而且支持性也超级好. IE8+ 啊,亲~ 但是IE 是使用XDomainRequest 发送的.(真丑的一逼)