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. iOS SDK开发汇总

    以前也做过静态库的开发,不过都是一些简单的调用,最近在做项目的时候,发现其中还有很多问题,所以建个小项目简单记录遇到的问题以及正确的解决办法. 在项目中遇到的问题如下:xib文件获取不到, story ...

  2. Markdown字体大小与颜色

    Markdown是一种可以使用普通文本编辑器编写的标记语言,通过类似HTML的标记语法,它可以使普通文本内容具有一定的格式.但是它本身是不支持修改字体.字号与颜色等功能的!   CSDN-markdo ...

  3. 【Java并发编程】18、PriorityBlockingQueue源码分析

    PriorityBlockingQueue是一个基于数组实现的线程安全的无界队列,原理和内部结构跟PriorityQueue基本一样,只是多了个线程安全.javadoc里面提到一句,1:理论上是无界的 ...

  4. 二进制值和十六进制字符串相互转换的C++代码

    #include <iostream> #include <string> #include <stdint.h> using namespace std; str ...

  5. SQL Server 创建和修改数据表

    一.CREATE语句(创建) 1.创建DataBase 1.CONTAINMENT SQL Server 2012 新功能 , 默认值是OFF .(太高级 书上也没有详细介绍). 2.ON ON用于两 ...

  6. 深入研究HTML5实现图片压缩上传

    上篇文章中提到移动端上传图片,我们知道现在流量还是挺贵的,手机的像素是越来越高,拍个照动不动就是好几M,伤不起.虽然客户端可以轻轻松松实现图片压缩再上传,但是我们的应用还可能在浏览器里面打开,怎么办呢 ...

  7. 【代码笔记】Web-手机端的meta

    一,天猫 <title>天猫触屏版</title> <meta content="text/html; charset=utf-8" http-equ ...

  8. Python自动化开发之python的常用模块

    python常用模块 模块的种类:模块分为三种,分别是自定义模块:内置标准模块(即标准库):开源模块(第三方). 以下主要研究标准模块即标准库:标准库直接导入即可,不需要安装. 时间模块:time , ...

  9. Linux 学习笔记之超详细基础linux命令 Part 1

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122   说明:主要是在REHL Server 6操作系统下进行的测试 --字符界面虚拟终端与图形界面之间的切 方法:[ ...

  10. MVC与单元测试实践之健身网站(七)-添加计划

    ​计划的制定涉及到周期-动作包-动作的关联操作,在上一篇<计划的添加与重置>完成了周期的设置.动作包的添加,现在要完成的是动作的添加操作. 一 具体功能 a) 在选定了一个大周期具有的天数 ...