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通信原理图
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独立的数据帧。如下图所示,为协议帧格式:
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('<center><h1>WebSocket Test</h1></center>')
})
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系统中,希望大家持续关注……