WebSocket原理与实践(二)---WebSocket协议

WebSocket协议是为了解决web即时应用中服务器与客户端浏览器全双工通信问题而设计的。协议定义ws和wss协议,分别为普通请求和基于SSL的安全传输, ws端口是80,wss的端口为443.

WebSocket协议由两部分组成,握手和数据传输。

2-1 握手
WS的握手使用HTTP来实现的。客户端的握手消息是一个普通的,带有Upgrade头的,HTTP Request的消息。
先来看看如下代码:

websocket

页面运行后,我们可以看到链接到 wss://echo.websocket.org 期间记录的一个握手协议。先来看看客户端发送http的请求头:

GET /chat HTTP/1.1 Host:echo.websocket.org Upgrade:websocket Connection:Upgrade Sec-WebSocket-Key:ALS2AoBJtUup67heKDgzFg== Origin:file:// Sec-WebSocket-Version:13

服务器响应的头字段

Connection:Upgrade
Sec-WebSocket-Accept:qyzx/EgbRK15QNmr5PhpMQrPZMM=
Server: Kaazing Gateway
Upgrade:websocket

下面是请求和响应头字段的含义:
Upgrade: websocket, 告诉服务器这个HTTP链接是升级的WebSocket协议。
Connection:Upgrade 告知服务器当前请求链接是升级的。
Origin: 该字段是用来防止客户端浏览器使用脚本进行未授权的跨源攻击,服务器要根据这个字段是否接受客户端的socket链接。
可以返回一个HTTP错误状态码来拒绝连接。

Sec-WebSocket-Key: ALS2AoBJtUup67heKDgzFg== 
Sec-WebSocket-Accept: qyzx/EgbRK15QNmr5PhpMQrPZMM=

Sec-WebSocket-Key 的值是一串长度为24的字符串是客户端随机生成的base64编码的字符串,它发送给服务器,服务器需要使用它经过一定的运算规则生成服务器的key,然后把服务器的key发到客户端去,客户端验证正确后,握手成功。

握手的具体原理:当我们客户端执行 new WebSocket(''wss://echo.websocket.org')的时候,客户端就会发起请求报文进行握手申请,报文中有一个key就是
Sec-WebSocket-Key,服务器获取到key,会将这个key与字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11相连,对新的字符串通过sha1安全散列算法计算出结果后,再进行Base64编码,并且将结果放在请求头的"Sec-WebSocket-Accept",最后返回给客户端,
客户端进行验证后,握手成功。握手成功后就可以开始数据传输了。

下面是实现一个简单的握手协议的demo,代码如下:

### 目录结构如下:

demo 
  |--- hands.html
  |--- hands.js

hands.html 代码如下:

WebSocket Demo

hands.js 代码如下:

var crypto = require('crypto'); var WS = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; require('net').createServer(function(o) { var key; o.on('data', function(e) { if (!key) { console.log(e); key = e.toString().match(/Sec-WebSocket-Key: (.+)/)[1]; console.log(key); // WS的字符串 加上 key, 变成新的字符串后做一次sha1运算,最后转换成Base64 key = crypto.createHash('sha1').update(key+WS).digest('base64'); console.log(key); // 输出字段数据,返回到客户端, o.write('HTTP/1.1 101 Switching Protocol\r\n'); o.write('Upgrade: websocket\r\n'); o.write('Connection: Upgrade\r\n'); o.write('Sec-WebSocket-Accept:' +key+'\r\n'); // 输出空行,使HTTP头结束 o.write('\r\n'); } else { // 数据处理 } }) }).listen(8000);

首先在命令行中 进入相对应项目目录后,运行 node hands.js, 然后打开 hands.html 运行一下即可看到 命令行中打印出来如下信息:

$ node hands.js

+iHlfGTolBaWYpnyTIw22g==
W7IEsdQtwv8EP2204kssK/6pg+c=

然后在浏览器中查看请求头如下信息:

Request Headers:

Connection:Upgrade Host:127.0.0.1:8000 Origin:file:// Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits Sec-WebSocket-Key:+iHlfGTolBaWYpnyTIw22g== Sec-WebSocket-Version:13 Upgrade:websocket

响应头如下信息:

Response Headers:

Connection:Upgrade
Sec-WebSocket-Accept:W7IEsdQtwv8EP2204kssK/6pg+c=
Upgrade:websocket

如上信息可以看到,获取报文中的key代码:
key = e.toString().match(/Sec-WebSocket-Key: (.+)/)[1];
console.log(key); // 打印 +iHlfGTolBaWYpnyTIw22g==

和 Request Headers:中的 Sec-WebSocket-Key 值是一样的,该值是浏览器自动生成的,然后获取该值后,与 '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',相连,对新的字符串通过sha1安全散列算法计算出结果后,再进行Base64编码,
并且将结果放在请求头的"Sec-WebSocket-Accept",最后返回给客户端,客户端进行验证后,握手成功。在浏览器中可以看到打印出 握手成功了。

github上查看demo

你可能感兴趣的:(c++)