websocket基本使用 前言
HTTP 协议有一个缺陷:通信只能由客户端发起。举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。
早期,很多网站为了实现推送技术,所用的技术都是轮询(也叫短轮询)。轮询是指由浏览器每隔一段时间向服务器发出 HTTP 请求,然后服务器返回最新的数据给客户端。 这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而 HTTP 请求与响应可能会包含较长的头部,其中真正有效的数据可能只是很小的一部分,所以这样会消耗很多带宽资源。
websocket简介
WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层,它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
建立在 TCP 协议之上,服务器端的实现比较容易。
与 HTTP 协议有着良好的兼容性。默认端口也是80和443 ,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。 数据格式比较轻量,性能开销小,通信高效。 可以发送文本,也可以发送二进制数据 。 没有同源限制,客户端可以与任意服务器通信。 协议标识符是 (如果加密,则为 ),服务器网址就是 URL。

简单实现
服务端
服务端需要安装websocket模块。已koa服务器为例npm install ws --save
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 const path = require ('path' )const fileUtils = require ('../utils/file_utils' )const WebSocket = require ('ws' )const wss = new WebSocket .Server ({ port : 9998 }) wss.on ('connection' , client => { console .log ('有客户端连接成功了...' ) client.on ('message' , async msg => { console .log ('客户端发送数据给服务端了: ' + msg) let payload = JSON .parse (msg) const action = payload.action if (action === 'getData' ) { let filePath = '../data/' + payload.chartName + '.json' filePath = path.join (__dirname, filePath) const ret = await fileUtils.getFileJsonData (filePath) payload.data = ret client.send (JSON .stringify (payload)) } else { wss.clients .forEach (client => { client.send (msg) }) } }) })
客户端
客户端运行在浏览器,本身已经存在websocket对象可以直接使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <button id="connect">连接</button> <button id="send" disabled="true">发送数据</button> <br> 从服务端接收的数据如下: <br> <span id="recv"></span> <script> var connect = document.querySelector('#connect') var send = document.querySelector('#send') var recv = document.querySelector('#recv') let ws = null connect.onclick = function(){ ws = new WebSocket('ws://localhost:9998') ws.onopen = () => { console.log('连接服务端成功了...') send.disabled = false } ws.onclose = () => { console.log('连接服务器失败/关闭') send.disabled = true } ws.onmessage = msg => { console.log('接收到从服务端发送过来的数据了') console.log(msg) recv.innerHTML = msg.data } } send.onclick = function(){ ws.send(JSON.stringify({ action: 'themeChange', socketType: 'themeChange', chartName: '', value: 'chalk' })) } </script> </body> </html>
websocket常用方法
WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
1 var Socket = new WebSocket (url, [protocol] );
属性
socket指的是websocket实例,例如上面例子的wss、ws
属性
描述
Socket.readyState
只读属性 readyState 表示连接状态,可以是以下值: 0 - 表示连接尚未建立。 1 - 表示连接已建立,可以进行通信。 2 - 表示连接正在进行关闭。 3 - 表示连接已经关闭或者连接不能打开。
Socket.bufferedAmount
只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 switch (ws.readyState ) { case WebSocket .CONNECTING : break ; case WebSocket .OPEN : break ; case WebSocket .CLOSING : break ; case WebSocket .CLOSED : break ; default : break ; }
事件
事件
事件处理程序
描述
open
Socket.onopen
连接建立时触发
message
Socket.onmessage
客户端接收服务端数据时触发
error
Socket.onerror
通信发生错误时触发
close
Socket.onclose
连接关闭时触发
方法
方法
描述
Socket.send()
使用连接发送数据
Socket.close()
关闭连接