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

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

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

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

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>websocket</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
</head>
<body>
<script type="text/javascript">
var wsUrl = "wss://echo.websocket.org";
var ws = new WebSocket(wsUrl);
ws.onopen = function() {
console.log('open');
};
ws.onmessage = function(msg) {
console.log(msg.data);
}
ws.onclose = function() {
console.log('已经被关闭了');
}
</script>
</body>
</html>

页面运行后,我们可以看到链接到 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 代码如下:

<html>
<head>
<title>WebSocket Demo</title>
</head>
<body>
<script type="text/javascript">
var ws = new WebSocket("ws://127.0.0.1:8000");
ws.onerror = function(e) {
console.log(e);
};
ws.onopen = function() {
console.log('握手成功');
}
</script>
</body>
</html>

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
<Buffer 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 3a 38 30 30 30 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 ... >
+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

WebSocket原理与实践(二)---WebSocket协议的更多相关文章

  1. [从Paxos到ZooKeeper][分布式一致性原理与实践]<二>一致性协议[Paxos算法]

    Overview 在<一>有介绍到,一个分布式系统的架构设计,往往会在系统的可用性和数据一致性之间进行反复的权衡,于是产生了一系列的一致性协议. 为解决分布式一致性问题,在长期的探索过程中 ...

  2. WebSocket原理与实践(一)---基本原理

    WebSocket原理与实践(一)---基本原理 一:为什么要使用WebSocket?1. 了解现有的HTTP的架构模式:Http是客户端/服务器模式中请求-响应所用的协议,在这种模式中,客户端(一般 ...

  3. WebSocket原理与实践(四)--生成数据帧

    WebSocket原理与实践(四)--生成数据帧 从服务器发往客户端的数据也是同样的数据帧,但是从服务器发送到客户端的数据帧不需要掩码的.我们自己需要去生成数据帧,解析数据帧的时候我们需要分片. 消息 ...

  4. WebSocket原理与实践(三)--解析数据帧

    WebSocket原理与实践(三)--解析数据帧 1-1 理解数据帧的含义:   在WebSocket协议中,数据是通过帧序列来传输的.为了数据安全原因,客户端必须掩码(mask)它发送到服务器的所有 ...

  5. WebSocket原理与实践

    开题思考:如何实现客户端及时获取服务端数据? Polling 指客户端每隔一段时间(周期性)请求服务端获取数据,可能有更新数据返回,也可能什么都没有,它并不在乎服务端数据有无更新.(Web端一般采用a ...

  6. RPC原理与实践(二)----Thrift分层模型

    这一节我们从一下几个方面来讲一下Thrift的分层架构,按照官方的定义这是Thrift的网络栈,其中网络栈中分为一下几个部分,(由栈顶到栈底)server,processor,protocol,tra ...

  7. HTML5(十二)——一文读懂 WebSocket 原理

    一.WebSocket 由来 WebSocket 是一个持久化的协议,通过第一次 HTTP Request 建立连接之后,再把通信协议升级成 websocket,保持连接状态,后续的数据交换不需要再重 ...

  8. 萌萌的websocket原理解析

    转载自:http://www.zhihu.com/question/20215561 一.WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持 ...

  9. WebSocket原理及与http1.0/1.1 long poll和 ajax轮询的区别【转自知乎】

    一.WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)首先HTTP有1.1和1.0之说,也就是所谓的ke ...

随机推荐

  1. GBK与UTF-8的区别

    GBK的文字编码是双字节来表示的,即不论中.英文字符均使用双字节来表示,只不过为区分中文,将其最高位都定成1. 至于UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节) ...

  2. 14-补充内容:MySQl创建用户和授权

    [转]14-补充内容:MySQl创建用户和授权 权限管理 我们知道我们的最高权限管理者是root用户,它拥有着最高的权限操作.包括select.update.delete.update.grant等操 ...

  3. 浅析requests库响应对象的text和content属性

    在做爬虫时请求网页的requests库是必不可少的,我们常常会用到 res = resquests.get(url) 方法,在获取网页的html代码时常常使用res的text属性: html = re ...

  4. 【20190123】JavaScript-轮播图特效中出现的问题

    使用纯html和JavaScript实现焦点轮播图特效,本来之前用setInterval()函数写的一个简单的循环轮播图,但是出现了两个问题:   1. 当网页被切换时,也就是网页失去焦点时,计时器函 ...

  5. loadrunner 11 安装与使用

    注:以下链接均为转载,详细内容请查看原文. 安装教程: https://blog.csdn.net/u010731693/article/details/78986840 使用教程: https:// ...

  6. 简单的TabLayout+Fragment选项卡

    TabLayout属性: app:tabIndicatorColor="#fff"  //下方滚动的下划线颜色 app:tabIndicatorHeight="10dp& ...

  7. Flutter 布局(七)- Row、Column详解

    本文主要介绍Flutter布局中的Row.Column控件,详细介绍了其布局行为以及使用场景,并对源码进行了分析. 1. Row A widget that displays its children ...

  8. memcached分析

    memcache介绍 memcache是一个高性能的分布式的内存对象缓存系统,用于动态Web应用以减轻数据库负担.它通过在内存中缓存数据和对象,来减少读取数据库的次数.从而提高动态.数据库驱动网站速度 ...

  9. BootStrap DateTimePicker的使用

    使用方法 1. 添加资源 2. 编写代码 <!DOCTYPE html> <html> <head> <meta http-equiv="Conte ...

  10. gitlab hooks配置

    1.邮件格式过滤 pre-recieive rev_type=commit # Only check the first commit information due to a lot of comm ...