WebSockets和EvnentSource简单对比&基本使用

2021/11/28 Websocket Javascript 共 3004 字,约 9 分钟

Websockets

特点

  • 同源策略对WebSockets不适用,可以通过该协议打开任意站点的连接。是否进行通信完全取决于服务器对请求方的控制。
  • WebSockets只能通过连接发送纯文本数据,所以对于复杂的数据结构,必须进行序列化再发送。
  • 全双工通信,即可以双向通信。
  • 协议标志符是 ws|wss

优点

  • 建立在TCP协议之上,服务器实现比较容易
  • 与HTTP协议有着良好的兼容性,默认端口也是80和443,并且握手阶段采用HTTP协议,因此握手不容易被屏蔽,能通过各种HTTP代理服务器
  • 数据格式比较轻量,性能开销小,通信高效
  • 可以发送文本,也能发送二进制数据(blob对象或ArrayBuffer对象)
  • 没有同源策略限制,客户端可以与任意服务器通信

使用

1、基本使用

const ws = new WebSocket(url)

ws.onopen = function(e) {
  ws.send('hola ws')
}
ws.onmessage = function(e) {
  const data = e.data
  console.log('data: ', data)
  ws.close()
}
ws.onclose = function(e) {}
ws.onerror = function(e) {}

// 可以使用ws.addEventListener的方式

2、发送blob对象数据

const file = document.querySelector('input[type=file]').files[0]
ws.send(file)

3、发送ArrayBuffer对象数据

const img = canvas_context.getImageData(0, 0, 400, 320)
const binary = img.data.reduce((a, c, i) => {
  a[i] = c
  return a
}, new Unit8Array(img.data.length))
ws.send(binary.buffer)

4、判断服务器返回的数据类型

ws.addEventListener('message', function(e) {
  const data = e.data
  if (typeof data === 'string') {
    // handle with text data string
  }
  if (data instanceof ArrayBuffer) {
    // handle with binary data
  }
}, false)

5、判断二进制数据是否发送完成

const data = new ArrayBuffer(1000000)
ws.send(data)

if (ws.bufferedAmount === 0) {
  // data is send done
} else {
  // binary data is sending
}

WebSocket in linux

1、counter.sh

#!/bin/bash

echo 1
sleep 1
echo 2
sleep 2
echo 3

bash ./counter.sh will output 1 2 3

2、install websocketd

# execute shell server-side
websocketd --port=8080 bash ./counter.sh
// accept data client-side
const ws = new WebSocket('ws://<serverIp>:8080/')
ws.onmessage = function(ev) {
  const data = ev.data
  // will output 1 2 3
  console.log('data: ', data);
}

3、监听服务器文件变动

# execute shell server-side
websocketd --port=8080 ls

EventSource

SSE(Server-Send-Events)本质

严格的说,HTTP协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(steaming)。

也就是说,发送的不适一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发送来的新的数据流,视频播放就是这样的例子。

本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。

SSE就是利用这种机制,使用流信息向浏览器推送信息。它基于HTTP协议,支持广泛。

特点

  • 单向通信,只能服务器向客户端推送事件,Content-Type: text/event-stream
  • 本质是一种流信息,流信息,即下载,如果浏览器向服务器发送数据,就变成了另一次HTTP请求。
  • 遵循同源策略.

优点

  • SSE使用HTTP协议,现有的服务器软件都支持,不需要额外改造。不同于WebSockets的是,WebSockets是一个独立协议,需要服务器单独支持。
  • 轻量级,使用简单;WebSockets协议相对复杂。
  • 默认支持断线重连;WebSockets需要自己实现。
  • SSE一般只用来传送文本,二进制数据需要编码后传送;WebSockets 默认支持传送二进制数据.
  • SSE支持自定义发送的消息类型.

断线重连

服务器向浏览器发送的SSE数据,必须是utf-8编码的文本,并且具有以下HTTP头信息.

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

每一次发送的信息,由若干个message组成. 数据标识符用id字段表示,相当于每一条数据的编号.

id: msg1\n
data: message\n\n

一旦连接断线,浏览器就会发送一个HTTP头,里面包含一个特殊的头部字段Last-Event-Id,用来帮助服务器重建连接.

使用

1、判断是否支持SSE

if ('EventSource' in window) {}

2、跨域访问

跨域时需要在服务器端做跨域头配置;跨域时,可以选择是否同步发送cookie.

const eventSource = new EventSource(url, {
  withCredentials: true,
})

3、基本使用

const eventSource = new EventSource(url)

eventSource.onopen = function(event) {}
eventSource.onmessage = function(event) {
  const data = event.data
  // handle with data
}
eventSource.onerror = function(event) {}
evnetSource.close()

// or
eventSource.addEventListener('open', function(event) {}, false)
eventSource.addEventListener('message', function(event) {
  const data = event.data
  // handle with data
}, false)
eventSource.addEventListenter('error', function(event) {}, false)

4、自定义事件

自定义事件以后,服务器发送来的数据,就不再会触发message事件

eventSource.addEventListener('eventName', function(event) {}, false)

Search

    Table of Contents