WebSocket 学习笔记

WebSocket一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。WebSocket API也被W3C定为标准。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

背景

现在,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
而比较新的技术去做轮询的效果是Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
Websocket使用ws或wss的统一资源标志符,类似于HTTPS,其中wss表示在TLS之上的Websocket。如:

ws://example.com/wsapi
wss://secure.example.com/

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

其他特点包括:

  1. 建立在 TCP 协议之上,服务器端的实现比较容易。
  2. 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
  3. 数据格式比较轻量,性能开销小,通信高效。
  4. 可以发送文本,也可以发送二进制数据。
  5. 没有同源限制,客户端可以与任意服务器通信。
  6. 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

握手协议

WebSocket 是独立的、创建在 TCP 上的协议。
Websocket 通过 HTTP/1.1 协议的101状态码进行握手。
为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(handshaking)。

Property and Method

WebSocket 对象提供了一组用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。

WebSocket构造器方法接受一个必须的参数和一个可选的参数:

WebSocket WebSocket(in DOMString url, in optional DOMString protocols);
WebSocket WebSocket(in DOMString url,in optional DOMString[] protocols);

参数

url
表示要连接的URL。这个URL应该为响应WebSocket的地址。
protocols 可选
可以是一个单个的协议名字字符串或者包含多个协议名字字符串的数组。这些字符串用来表示子协议,这样做可以让一个服务器实现多种WebSocket子协议(例如你可能希望通过制定不同的协议来处理不同类型的交互)。如果没有制定这个参数,它会默认设为一个空字符串。
构造器方法可能抛出以下异常:

SECURITY_ERR
试图连接的端口被屏蔽。
方法概述
void close(in optional unsigned long code, in optional DOMString reason);
void send(in DOMString data);

属性

  • binaryType [DOMString] 一个字符串表示被传输二进制的内容的类型。取值应当是”blob”或者”arraybuffer”。”blob”表示使用DOMBlob 对象,而”arraybuffer”表示使用 ArrayBuffer 对象。

  • bufferedAmount [unsigned long] 调用 send() 方法将多字节数据加入到队列中等待传输,但是还未发出。该值会在所有队列数据被发送后重置为 0。而当连接关闭时不会设为0。如果持续调用send(),这个值会持续增长。只读。

  • extensions [DOMString] 服务器选定的扩展。目前这个属性只是一个空字符串,或者是一个包含所有扩展的列表。
    onclose EventListener 用于监听连接关闭事件监听器。当 WebSocket 对象的readyState 状态变为 CLOSED 时会触发该事件。这个监听器会接收一个叫close的 CloseEvent 对象。

  • onerror [EventListener] 当错误发生时用于监听error事件的事件监听器。会接受一个名为“error”的event对象。

  • onmessage [EventListener] 一个用于消息事件的事件监听器,这一事件当有消息到达的时候该事件会触发。这个Listener会被传入一个名为”message”的 MessageEvent 对象。

  • onopen [EventListener] 一个用于连接打开事件的事件监听器。当readyState的值变为 OPEN 的时候会触发该事件。该事件表明这个连接已经准备好接受和发送数据。这个监听器会接受一个名为”open”的事件对象。

  • protocol [DOMString] 一个表明服务器选定的子协议名字的字符串。这个属性的取值会被取值为构造器传入的protocols参数。

  • readyState [unsigned short] 连接的当前状态。取值是 Ready state constants之一。 只读。

  • url [DOMString] 传入构造器的URL。它必须是一个绝对地址的URL。只读。

常量

Ready state 常量:用来描述 WebSocket 连接的状态。

  • CONNECTING 0 连接还没开启。
  • OPEN 1 连接已开启并准备好进行通信。
  • CLOSING 2 连接正在关闭的过程中。
  • CLOSED 3 连接已经关闭,或者连接无法建立。

方法

close()

关闭WebSocket连接或停止正在进行的连接请求。如果连接的状态已经是closed,这个方法不会有任何效果

void close(in optional unsigned short code, in optional DOMString reason);
参数

code 可选
一个数字值表示关闭连接的状态号,表示连接被关闭的原因。如果这个参数没有被指定,默认的取值是1000 (表示正常连接关闭)。 请看CloseEvent页面的 list of status codes来看默认的取值。
reason 可选
一个可读的字符串,表示连接被关闭的原因。这个字符串必须是不长于123字节的UTF-8 文本(不是字符)。
可能抛出的异常

INVALID_ACCESS_ERR
选定了无效的code。
SYNTAX_ERR
reason 字符串太长或者含有unpaired surrogates。
注意: 在Gecko中,Gecko 8.0 (Firefox 8.0 / Thunderbird 8.0 / SeaMonkey 2.5)之间的版本的实现不支持任何参数。

send()

通过WebSocket连接向服务器发送数据。

void send(in DOMString data);
void send(in ArrayBuffer data);
void send(in Blob data);
参数

data
要发送到服务器的数据。
可能抛出的异常

INVALID_STATE_ERR
当前连接的状态不是OPEN。
SYNTAX_ERR
数据是一个包含unpaired surrogates的字符串。
注意: Gecko 6.0实现的send()方法与规范的要求有一些不同。Gecko会返回一个 boolean表示连接是否依然处于开启状态 (并且这个数据被成功放入的发送队列或者被发送)。在 Gecko 8.0中这个问题被修正了。

学习连接

WebSocket 阮一峰的网络日志

WebSocket实战(useful)

WebSocket 实例注解开发(useful)