WebSocket

在H5,js代码新增了WebSocket的API。这玩意儿,从使用上来说,不难,也就onopen、onclose、onmessage、onerror这几个接口而已,前段时间使用的时候,就还是不由自主地去看一些这方面的东西。

Websocket是基于TCP协议上实现的,也有借助HTTP协议,但与HTTP1.X协议不同地方是,WebSocket是长连接,双方只需要一个握手动作(这里是借助HTTP协议),就可以建立一条连接通道,接着就能相互传输数据了;而HTTP1.X是短连接的,每次发起请求都要在TCP层来个3次握手,数据传输完或到指定的超时时间后就断开连接,若要多次请求,就要不断发起请求,这样挺占带宽。
Websocket在服务器方面,只需增加支持即可,如Python的tornado框架就支持,golang也挺多的,但我用的是大猩猩:gorilla。web服务器上,nginx在1.3.13版本也支持;其他web server,自行去搜索吧。浏览器方面除了老IE系,其他浏览器目前的新版本基本都支持WebSocket。

Javascript的接口

var conn = new WebSocket("ws://ip:port/");
conn.onclose = function(evt) {
    console.log(evt);
}

conn.onmessage = function(evt) {
    console.log(evt);
}

conn.onopen = function(evt) {
    console.log(evt);
}

conn.onerror = function(evt) {
    console.log(evt);
}

各接口看名称就知道是什么意思了。
浏览器与服务端建立连接的时候,要经过一个Websocket握手协议

GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 172.16.1.11
Origin: http://example.com
Sec-WebSocket-Key: BVuKSx8KJKN2VAGM0i6gjw==
Sec-WebSocket-Version: 13

这是正常的HTTP的GET请求,然后在请求头里增加了

Upgrade: websocket
Connection: Upgrade

这等于告诉web服务器,发起的请求是Websocket协议的,要用Websocket协议方式来处理请求。

在请求头里,还增加了

Sec-WebSocket-Key: BVuKSx8KJKN2VAGM0i6gjw==

看值的话,就应该能猜到,是通过BASE64编码而成的值,这是浏览器随机生成的。

HTTP响应头
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: sr0Tsn4bYggO1mzRZHpiOQO+FYE=

Sec-WebSocket-Accept这个是通过服务器确认,并加密后的Sec-WebSocket-Key。下面的这个响应头代表告诉客户端,升级成Websocket协议,属于HTTP最后负责地方

Upgrade: websocket
Connection: Upgrade

为什么说是HTTP最后负责的地方?因为WebSocket只是借助了HTTP协议去握手,仅此而已。此后信息通讯时,并不基于HTTP协议,而是基于更底层的TCP协议。WebSocket是一个和HTTP协议一样是基于TCP协议上的应用层协议。

数据收发

Websocket是可以发数据类型消息,也可以发控制类型消息。
数据类型消息包含:纯文本消息,二进制消息
控制类型消息包含:Ping,Pong,Close

更准确的说,WebSocket消息传输包含数据帧和控制帧,控制帧包含Ping,Pong,Close

这3个帧的Opcode各不相同:
  1. Ping帧的Opcode是9,0x09
  2. Pong帧的Opcode是10,0x0A
  3. Close帧的Opcode是8,0x08
数据帧包含文本帧和二进制帧
  1. 文本帧的Opcode是1,0x01
  2. 二进制帧的Opcode是2,0x02

还有一个既非数据帧,也非控制帧,是0x00,代表继续帧。
通过上面几个数字看到,还缺了几个数字,这几个缺了的数字是协议保留,以备后用。

保留帧
  1. 0x03——0x07:保留用于未来的非控制帧
  2. 0x0B——0x0F:保留用于未来的控制帧

还有其他的具体解释在:传送门

ping帧的数据传输
WebSocket_第1张图片
ping

可以看到opcode是数字9

pong帧的数据传输
WebSocket_第2张图片
pong

可以看到opcode是数字10

close帧

下图是服务器主动断开连接,opcode为10,在红框处,有一个十六进制的数字,还有一串英文解释。
第一个Close表示的是关闭的代码,第二个Close表示的是关闭的原因。
关闭的reason也可以自定义,但reason内容的长度别过长(之前试过大概在128个字节左右,具体的可以再试试),否则数据传输不了导致无法断开的问题。
websocket的状态码具体详解在这:传送门

WebSocket_第3张图片
92701058-92E0-4E07-AFDA-2F394CD66CF1.png

在js的接口中,没有主动发起ping接口的调用,这一般是在服务器那发起ping请求,浏览器接收到ping帧后,就会回个pong帧,从而达到心跳效果。

发送文本数据

从web界面向服务器发送32个‘f’,截取传输数据如下图:


WebSocket_第4张图片
C4B0F5CA-49D3-4F27-8193-ABA7A52DB91D.png

Payload length代表数据长度。以字节的形式表示:7位、7+16位、或者7+64位。如果这个值以字节表示是0-125这个范围,那这个值就表示传输数据的长度;如果这个值是126,则随后的两个字节表示的是一个16进制无符号数,用来表示传输数据的长度;如果这个值是127,则随后的是8个字节表示的一个64位无符号数,这个数用来表示传输数据的长度。多字节长度的数量是以网络字节的顺序表示。负载数据的长度为扩展数据及应用数据之和,扩展数据的长度可能为0,因而此时负载数据的长度就为应用数据的长度。Payload length不包括Masking-key在内。
Masking-key,呃,掩码键。
还有好多其他说明,都去传送门里看吧。。

其他

之前在网上无意间看到这图,觉得挺不错的,描述建立连接时,websocket和TCP层的握手关系,很一目了然


WebSocket_第5张图片
handshake

在建立建立之后,每次端对端之间发送数据,另一端在TCP层都会回发个ACK表示确认。
WebSocket只是个协议,不是只能运行在浏览器上,自行用手机/其他客户端也可以实现,只需遵循协议即可(目前协议文档是RFC6455),个人觉得,假如没有其他更好想法,用这个协议来代替很多TCP层的数据传输格式也是不错的。

还有一个是IBM公司搞的MQTT协议,之前了解过其主要用于嵌入式设备,说是比较省电(相对于HTTP协议来比较那的确是),使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合。它跟Websocket一样也是基于TCP协议的,都有各自的协议头格式。

呃,网上搜的时候,很多人都有对这些方面研究了,解释的更好
张善友

你可能感兴趣的:(WebSocket)