WebSocket 和 HTTP 的区别及原理
- HTTP 协议有一个缺陷:通信只能由客户端发起。
- 这种单向请求的特点只能使用”轮询”,每隔一段时候,就发出一个询问,了解服务器有没有新的信息。但是效率低,非常浪费资源
WebSocket
最大特点:服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种
- 2008 年诞生,2011 年成功国际标准,所有浏览器支持
其他特点:
- 建立在 TCP 协议之上,服务器端的实现比较容易。
- 与 HTTP 协议有着良好的兼容性。默认端口也是 80 和 443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是 ws(如果加密,则为wss),服务器网址就是 URL。如 ws://example.com:80/some/path
用法
- 创建一个WebSocket实例:
var ws = new WebSocket('wss://echo.websocket.org')
- 调用onopen,用于指定连接成功后的回调函数
1
2
3
4ws.onopen = function (evt) {
console.log('Connection open ...')
ws.send('Hello WebSockets!')
} - 调用onmessage,用于指定收到服务器数据后的回调函数
1
2
3
4ws.onmessage = function (evt) {
console.log('Received Message: ' + evt.data)
ws.close()
} - 调用onclose,用于指定连接关闭后的回调函数
1
2
3ws.onclose = function (evt) {
console.log('Connection closed.')
}
- 创建一个WebSocket实例:
客户端 API
WebSocket 对象作为一个构造函数,用于创建 WebSocket 实例
- 作用:执行后客户端就会与服务端进行连接
- 示例:const ws = new Websockett(‘ws://localhost:8080’)
webSocket.readyState
- 作用:返回实例对象的当前状态
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12switch (ws.readyState) {
case WebSocket.CONNECTING: // 值为0,表示正在连接
break
case WebSocket.OPEN: // 值为1,表示连接成功,可以通信了
break
case WebSocket.CLOSING: // 值为2,表示连接正在关闭
break
case WebSocket.CLOSED: // 值为3,表示连接已经关闭,或者打开连接失败
break
default:
break
}
webSocket.onopen
- 作用:用于指定连接成功后的回调函数
- 示例:ws.onopen = function () {ws.send(‘message’)}
- 如果要指定多个回调函数,可以使用 addEventListener 方法
- ws.addEventListener(‘open’,function (event) {ws.send(‘message’)})
webSocket.onclose
- 作用:用于指定连接关闭后的回调函数
- 示例:ws.onclose = function () {}
- 如果要指定多个回调函数,可以使用 addEventListener 方法
- ws.addEventListener(‘close’,function (event) {})
webSocket.onmessage
- 作用:用于指定收到服务器数据后的回调函数
- 示例:ws.onmessage = function(event) {var data = event.data}
- 如果要指定多个回调函数,可以使用 addEventListener 方法
- ws.addEventListener(‘message’,function (event) {var data = event.data})
- 如果服务器数据时文本或者二进制数据(blob 对象或 Arraybuffer 对象)
- 除了动态判断收到的数据类型,也可以使用 binaryType 属性,显式指定收到的二进制数据类型。
1
2
3
4
5
6
7
8
9
10
11
12
13ws.onmessage = function (event) {
if (typeof event.data === String) {}
if (event.data instanceof ArrayBuffer) {
var buffer = event.data
}
// 收到的是blob数据
ws.binaryType = 'blob'
ws.onmessage = function (e) {}
// 收到的是ArrayBuffer数据
ws.binaryType = 'arraybuffer'
ws.onmessage = function (e) {}
}
webSocket.send()
- 作用:用于向服务器发送数据。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12// 发送文本
ws.send('meaage')
// 发送Blob对象
var file = document.querySelector('input[type="file"]').files[0]
ws.send(file)
// 发送ArrayBuffer 对象
var img = canvas_context.getImageData(0, 0, 400, 320)
var binary = new Uint8Array(img.data.length)
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i]
}
ws.send(binary.buffer)
webSocket.bufferedAmount
- 作用:表示还有多少字节的二进制数据没有发送出去,可以用来判断发送是否结束
- 示例:
1
2
3
4
5
6
7var data = new ArrayBuffer(10000000)
ws.send(data)
if (ws.bufferedAmount === 0) {
// 发送完毕
} else {
// 发送还没结束
}
webSocket.onerror
- 作用:用于指定报错时的回调函数。
- 示例:ws.onerror = function (event) {}
- 如果要指定多个回调函数,可以使用 addEventListener 方法
- ws.addEventListener(‘error’,function (event) {})
服务端的实现
常用的 Node 实现有以下三种
WebSocketd — WebSocket 服务器
- 最大特点,就是后台脚本不限语言,标准输入(stdin)就是 WebSocket 的输入,标准输出(stdout)就是 WebSocket 的输出