WebSocket协议分析及实现

1.概述

Webscoket是Web浏览器和服务器之间的一种全双工通信协议,其中WebSocket协议由IETF定为标准,WebSocket API由W3C定为标准。一旦Web客户端与服务器建立起连接,之后的全部数据通信都通过这个连接进行。通信过程中,可互相发送JSON、XML、HTML或图片等任意格式的数据。
WS(WebSocket)与HTTP协议相比,相同点主要有:

  • 都是基于TCP的应用层协议;
  • 都使用Request/Response模型进行连接的建立;
  • 在连接的建立过程中对错误的处理方式相同,在这个阶段WS可能返回和HTTP相同的返回码;
  • 都可以在网络中传输数据。
    不同之处在于:
  • WS使用HTTP来建立连接,但是定义了一系列新的header域,这些域在HTTP中并不会使用;
  • WS的连接不能通过中间人来转发,它必须是一个直接连接;
  • WS连接建立之后,通信双方都可以在任何时刻向另一方发送数据;
  • WS连接建立之后,数据的传输使用帧来传递,不再需要Request消息;
  • WS的数据帧有序。
    WS整个通信过程如下图所示:


    WebSocket协议分析及实现_第1张图片
    WebSocket通信原理图

2.主要特点

推送功能:服务器可以直接向客户端推送消息。之前采取的方式都是客户端主动向服务器发送请求,这样比较耗费资源。
减少通信量:只要第一次建立连接,就可以一直进行通信,不像HTTP协议,需要频繁的建立请求,一问一答的模式。此外,Websocket的头部数据也比较少。

3.握手协议

websocket是基于TCP的一个应用协议,与HTTP协议的关联之处在于websocket的握手数据被HTTP服务器当作HTTP包来处理,主要通过Update request HTTP包建立起连接,之后的通信全部使用websocket自己的协议。
请求:TCP连接建立后,客户端发送websocket的握手请求,请求报文头部如下:

GET /chat HTTP/1.1
Host: server.example.com
**Upgrade: websocket**
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: https://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
  • 第一行为为请求的方法,类型必须为GET,协议版本号必须大于1.1
  • Upgrade字段必须包含,值为websocket
  • Connection字段必须包含,值为Upgrade
  • Sec-WebSocket-Key字段必须包含 ,记录着握手过程中必不可少的键值。
  • Sec-WebSocket-Protocol字段必须包含 ,记录着使用的子协议
  • Origin:作安全使用,防止跨站攻击,浏览器一般会使用这个来标识原始域

响应:服务器接收到请求后,返回状态码为101 Switching Protocols 的响应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
  • Sec-WebSocket-Accept字段是由握手请求中的Sec-WebSocket-Key字段生层的。
    握手成功后,通信不再使用HTTP协议,而采用WebSocket独立的数据帧。如下图所示,为协议帧格式:


    WebSocket协议分析及实现_第2张图片
    image

    图中各名词含义如下

FIN:1bit,是否为信息的最后一帧
RSV 1-3:1bit,备用,默认为0
opcode:4bit,帧类型
                         0x00 连续消息分片
                         0x01 文本消息分片
                         0x02 二进制消息分片
                         0x03 ~ 0x07 为将来的非控制消息片段保留测操作吗
                         0x08 连接关闭
                         0x09 心跳检查 ping
                         0x0a 心跳检查pong
                         0x0b ~ 0x0f 为将来的控制消息片段保留的操作码
MASK:定义传输的数据是否有加掩码,如果设置为1,掩码键必须放在masking-key区域,客户端发送给服务端的所有消息,此位的值都是1
payload length:7bit,传输数据长度,以字节为单位。当这个长度为7bit数字为126时,紧随其后的2个字节也是表示数据长度。当这个长度为7bit数字为127时,紧随其后的8个字节也是表示数据长度。
Masking-key:0或者4bit,只有当MASK设置为1时才有效。
Playload data:负载数据,为扩展数据和应用数据之和,Extension data + Application data。
Extension data:扩展数据,如果客户端和服务端没有特殊的约定,那么扩展数据长度始终为0
Application data:应用数据,

以上就是WebSocket协议帧的分析

4.实现

客户端

// websocket.js
+function( window ){
  // check whether your browser surpport the WebSocket Protocal
  if ( 'WebSocket' in window ) {
    var url = 'ws://127.0.0.1:8080';
    var ws = new WebSocket(url);
    var msgRecieved;
    
    ws.onopen = function () {
      console.log('Connected to websocket server ...');
    };

    ws.onmessage = function(e){
      msg = e.data;
      console.log('Message from server:' + e.data);
    };

    ws.onclose = function(e){
      console.log('Disconnected');
    }

    // send message to server
    ws.send('message from client');

  } else {
    console.error('Websocket is not supported by your browser!')
  }
  
}( window );

服务端

采用NodeJS+socket.io实现

# 安装模块
npm install --save express
npm install --save socket.io

服务端代码:

var app= require('express')()
var http = require('http').Server(app)
var io= require('socket.io').(http)

app.get('/', function(req, res){
  res.send('

WebSocket Test

') }) io.on('connection', function(socket){ console.log('There is a client connected!'); socket.on('disconnect', function(){ console.log('There is a client disconnected') socket.on('message', function(msg){ io.emit('message', msg) }) }) http.listen(8080, function(){ console.log('listening on *:8080') }) })

说明

后期,我会对WebSocket即时通信做进一步研究,并开发一个简易的在线聊天系统,加入到我的开源OA系统中,希望大家持续关注……

你可能感兴趣的:(WebSocket协议分析及实现)