ronghaoZHI/ronghaoZHI.github.io

websocket

Opened this issue · 0 comments

HTML5 之 WebSocket

WebSocket作为HTML5 的新特性,实现了浏览器与服务器全双工通信(full-duplex),可以传输基于消息的文本和二进制数据。 相比于 http协议的半双工通信,WebSocket 具有很大的优势。
WebSocket 是浏览器中最靠近套接字的API,除最初建立连接时需要借助于现有的HTTP协议,其他时候直接基于TCP完成通信。
如果项目对通信的实时性要求较高,或者有不断 polling 轮询相关的需求, 那么就可以尝试着使用WebSocket。

WebSocket和长轮询之间的带宽消耗差异:

image

WebSocket 协议帧

WebSocket 使用了自定义的二进制分帧格式,把每个应用消息切分成一或多个帧(!!!注意 ws会自动切分多帧,收到数据有乱码现象时应考虑是否有分帧情况),发送到目的地之后再组装起来,等到接收到完整的消息后再通知接收端。
在打开握手完成后,终端发送一个关闭帧之前的任何时间里,数据帧可能由客户端或服务器的任何一方发送。
image

FIN: 1 bit 。表示此帧是否是消息的最后帧,第一帧也可能是最后帧。
RSV1,RSV2,RSV3: 各1 bit 。必须是0,除非协商了扩展定义了非0的意义。
opcode: 4 bit。表示被传输帧的类型:x0 表示一个后续帧;x1 表示一个文本帧;x2 表示一个二进制帧;x3-7 为以后的非控制帧保留;x8 表示一个连接关闭;x9 表示一个ping;xA 表示一个pong;xB-F 为以后的控制帧保留。
Mask: 1 bit。表示净荷是否有掩码(只适用于客户端发送给服务器的消息)。
Payload length: 7 bit, 7 + 16 bit, 7 + 64 bit。 净荷长度由可变长度字段表示: 如果是 0~125,就是净荷长度;如果是 126,则接下来 2 字节表示的 16 位无符号整数才是这一帧的长度; 如果是 127,则接下来 8 字节表示的 64 位无符号整数才是这一帧的长度。
Masking-key: 0或4 Byte。 用于给净荷加掩护,客户端到服务器标记。
Extension data: x Byte。默认为0 Byte,除非协商了扩展。
Application data: y Byte。 在”Extension data”之后,占据了帧的剩余部分。
Payload data: (x + y) Byte。”extension data” 后接 “application data”。

WS / WSS

WebSocket 资源URI采用了自定义模式:ws 表示纯文本通信( 如:ws://http://example.com/socket),wss 表示使用加密信道通信(TCP+TLS)

ws协议:普通请求,占用与http相同的80端口;
wss协议:基于SSL的安全传输,占用与tls相同的443端口。

对应各自的URI如下:

 ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
 wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

WebSocket 的使用

浏览器提供的WebSocket API很简洁,调用示例如下:

 var ws = new WebSocket('ws://example.com/socket'); // 创建安全WebSocket 连接(wss)

 ws.onerror = function (error) { ... } // 错误处理
 ws.onclose = function () { ... } // 关闭时调用

 ws.onopen = function () { // 连接建立时调用
   ws.send("Connection established. Hello server!"); // 向服务端发送消息
 }

 ws.onmessage = function(msg) { // 接收服务端发送的消息
   if(msg.data instanceof Blob) { // 处理二进制信息
     processBlob(msg.data);
   } else {
     processText(msg.data); // 处理文本信息
   }
 }

WS 的属性及方法

属性:

readyState:
以下其中之一
0 (WebSocket.CONNECTING) 正在链接中
1 (WebSocket.OPEN) 已经链接并且可以通讯
2 (WebSocket.CLOSING) 连接正在关闭
3 (WebSocket.CLOSED) 连接已关闭或者没有链接成功

binaryType:
WebSocket.binaryType 返回websocket连接所传输二进制数据的类型。
返回值: "blob" (如果传输的是 Blob 类型的数据)、"arraybuffer" (如果传输的是 ArrayBuffer 类型的数据)

bufferedAmount:
WebSocket.bufferedAmount是一个只读属性,用于返回已经被send()方法放入队列中但还没有被发送到网络中的数据的字节数。一旦队列中的所有数据被发送至网络,则该属性值将被重置为0。但是,若在发送过程中连接被关闭,则属性值不会重置为0。如果你不断地调用send(),则该属性值会持续增长。

extensions:
WebSocket.extensions是只读属性,返回服务器已选择的扩展值。目前,链接可以协定的扩展值只有空字符串或者一个扩展列表。

onclose:
WebSocket.onclose 属性返回一个事件监听器,这个事件监听器将在 WebSocket 连接的readyState 变为 CLOSED时被调用。

onerror:
在 WebSocket.onerror 属性中,你可以定义一个发生错误时执行的回调函数,此事件的事件名为"error"
onmessage:
WebSocket.onmessage 属性是一个当收到来自服务器的消息时被调用的 EventHandler。

onopen:
WebSocket.onopen 属性定义一个事件处理程序,当WebSocket 的连接状态readyState 变为“OPEN”时调用;这意味着当前连接已经准备好发送和接受数据。

protocol:
WebSocket.protocol 是个只读属性,用于返回服务器端选中的子协议的名字;这是一个在创建WebSocket 对象时,在参数protocols中指定的字符串。

url:
WebSocket.url是一个只读属性,返回值为当构造函数创建WebSocket实例对象时URL的绝对路径。

方法:

WS 提供了可以 主动关闭 和 发送消息 两个方法
close()
WebSocket.close() 方法关闭 WebSocket 连接或连接尝试(如果有的话)。 如果连接已经关闭,则此方法不执行任何操作。

send()
WebSocket.send() 方法将需要通过 WebSocket 链接传输至服务器的数据排入队列,并根据所需要传输的data bytes的大小来增加 bufferedAmount的值 。若数据无法传输(例如数据需要缓存而缓冲区已满)时,套接字会自行关闭。