目录结构
 

一、什么是Websocket

websocket是html5提出的一个协议规范,参考rfc6455. 不过目前还都是在草案,没有成为标准,毕竟html5还在路上。

websocket约定了一个通信的规范,通过一个握手的机制,客户端(浏览器)和服务器(web server)之间能建立一个类似tcp的连接,从而方便c-s之间的通信。

在websocket出现之前,web交互一般是基于http协议的短连接或者长连接。

短连接的过程大概有下面几个步骤:

(1)建立tcp连接;

(2)浏览器发出http请求;

(3)web server应答;

(4)断开tcp连接;

优点是简洁明了,缺点也很明显,每一次的交互中,建立和断开tcp连接带来了比较大的开销,而且http协议头比较长,也会带来带宽的浪费。

通过设置http头中的keep-alive域可以实现http长连接,避免了建立和断开连接的开销,但是http协议头的问题仍然无法解决。

除此之外,web server主动向浏览器推送数据的处理会比较麻烦,要么是浏览器发起轮询(毫无疑问,这是一个低效的方式),或者利用comet技术,比较复杂,而且这已经不是在html层面上解决问题了。

而web socket的出现,解决了上面描述的问题。

二、Websocket握手协议

websocket是一种全新的协议,不属于http无状态协议,协议名为"ws",这意味着一个websocket连接地址会是这样的写法:ws://**。

websocket协议本质上是一个基于tcp的协议。建立连接需要握手,客户端(浏览器)首先向服务器(web server)发起一条特殊的http请求,web server解析后生成应答到浏览器,这样子一个websocket连接就建立了,直到某一方关闭连接。

由于是草案的原因,前前后后就出现了多个版本的握手协议,分情况说明一下:

(1) 基于flash的握手协议

使用场景是IE的多数版本,因为IE的多数版本不都不支持WebSocket协议,以及FF、CHROME等浏览器的低版本,还没有原生的支持WebSocket。此处,server唯一要做的,就是准备一个WebSocket-Location域给client,没有加密,可靠性很差。

客户端请求:

GET /ls HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: www.qixing318.com
Origin: http://www.qixing318.com

服务器返回:

HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin: http://www.qixing318.com
WebSocket-Location: ws://www.qixing318.com/ls

(2)基于md5加密方式的握手协议

客户端请求:

GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: **
Upgrade: WebSocket
Sec-WebSocket-Key1: **
Origin: http://www.qixing318.com
[8-byte security key]

服务端返回:

HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin: http://www.qixing318.com
WebSocket-Location: ws://example.com/demo
[16-byte hash response]

其中 Sec-WebSocket-Key1,Sec-WebSocket-Key2 和 [8-byte security key] 这几个头信息是web server用来生成应答信息的来源,依据 draft-hixie-thewebsocketprotocol-76 草案的定义。

web server基于以下的算法来产生正确的应答信息:

1)逐个字符读取 Sec-WebSocket-Key1 头信息中的值,将数值型字符连接到一起放到一个临时字符串里,同时统计所有空格的数量;

2)将在第(1)步里生成的数字字符串转换成一个整型数字,然后除以第(1)步里统计出来的空格数量,将得到的浮点数转换成整数型;

3)将第(2)步里生成的整型值转换为符合网络传输的网络字节数组;

4)对 Sec-WebSocket-Key2 头信息同样进行第(1)到第(3)步的操作,得到另外一个网络字节数组;

5)将 [8-byte security key] 和在第(3)、(4)步里生成的网络字节数组合并成一个16字节的数组;

6)对第(5)步生成的字节数组使用MD5算法生成一个哈希值,这个哈希值就作为安全密钥返回给客户端,以表明服务器端获取了客户端的请求,同意创建websocket连接

(3) 基于sha加密方式的握手协议

也是目前见的最多的一种方式,这里的版本号目前是需要13以上的版本。

客户端请求:

GET /ls HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: www.qixing318.com
Sec-WebSocket-Origin: http://www.qixing318.com
Sec-WebSocket-Key: 2SCVXUeP9cTjV+0mWB8J6A==
Sec-WebSocket-Version: 13

服务器返回:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: mLDKNeBNWz6T9SxU+o0Fy/HgeSw=

这个的原理,就是把客户端上报的key拼上一段GUID “258EAFA5-E914-47DA-95CA-C5AB0DC85B11″,拿这个字符串做SHA-1 hash计算,然后再把得到的结果通过base64加密,最后在返回给客户端。

三、Websocket数据帧

WebScoket协议中,数据以帧序列的形式传输,具体的协议标准可以参考rfc6455

(1)客户端向服务器传输的数据帧必须进行掩码处理:服务器若接收到未经过掩码处理的数据帧,则必须主动关闭连接。

(2)服务器向客户端传输的数据帧一定不能进行掩码处理。客户端若接收到经过掩码处理的数据帧,则必须主动关闭连接。
针对上情况,发现错误的一方可向对方发送close帧(状态码是1002,表示协议错误),以关闭连接。

FIN:1位

表示这是消息的最后一帧(结束帧),一个消息由一个或多个数据帧构成。若消息由一帧构成,起始帧即结束帧。

RSV1,RSV2,RSV3:各1位

MUST be 0 unless an extension is negotiated that defines meanings for non-zero values.

If a nonzero value is received and none of the negotiated extensions defines the meaning of such a nonzero value, the receiving endpoint MUST _Fail the WebSocket Connection_

大致意思是如果未定义扩展,各位是0;如果定义了扩展,即为非0值。如果接收的帧此处非0,扩展中却没有该值的定义,那么关闭连接。

OPCODE:4位

解释PayloadData,如果接收到未知的opcode,接收端必须关闭连接。

0×0表示附加数据帧

0×1表示文本数据帧

0×2表示二进制数据帧

0×3-7暂时无定义,为以后的非控制帧保留

0×8表示连接关闭

0×9表示ping

0xA表示pong

0xB-F暂时无定义,为以后的控制帧保留

MASK:1位

用于标识PayloadData是否经过掩码处理。如果是1,Masking-key域的数据即是掩码密钥,用于解码PayloadData。客户端发出的数据帧需要进行掩码处理,所以此位是1。

Payload length:7位,7+16位,7+64位, PayloadData的长度(以字节为单位)。

(1) 如果其值在0-125,则是payload的真实长度。

(2) 如果值是126,则后面2个字节形成的16位无符号整型数的值是payload的真实长度。注意,网络字节序,需要转换。

(3) 如果值是127,则后面8个字节形成的64位无符号整型数的值是payload的真实长度。注意,网络字节序,需要转换。

长度表示遵循一个原则,用最少的字节表示长度(我理解是尽量减少不必要的传输)。举例说,payload真实长度是124,在0-125之间,必须用前7位表示;不允许长度1是126或127,然后长度2是124,这样违反原则。

分片:

这种情况就比较复杂,具体可以参考rfc,一般在日常中用到的应该会比较少。

四、客户端API

websocket的客户端api描述可以参考这里,一个简单的代码参考:

<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function WebSocketTest() {
if ("WebSocket" in window) {
alert("WebSocket is supported by your Browser!");
// Let us open a web socket
var ws = new WebSocket("ws://localhost:9998/echo");
ws.onopen = function() {
// Web Socket is connected, send data using send()
ws.send("Message to send");
alert("Message is sent...");
};
ws.onmessage = function(evt) {
var received_msg = evt.data;
alert("Message is received...");
};
ws.onclose = function() {
// websocket is closed.
alert("Connection is closed...");
};
} else {
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}
}
</script>
</head>
<body>
<div id="sse">
<a href="javascript:WebSocketTest()">Run WebSocket</a>
</div>
</body>
</html>

五、服务器处理

目前开源的websocket server的代码还是不少的。

自己也整理过一份c的,支持上面三种握手情况,并嵌在reactor框架下使用,在chrome下测试过。

https://github.com/gaccob/gbase/blob/master/net/wsconn.h

https://github.com/gaccob/gbase/blob/master/net/wsconn.c

六、目前主流的浏览器支持情况

Chrome Supported in version 4+
Firefox Supported in version 4+
Internet Explorer Supported in version 10+
Opera Supported in version 10+
Safari Supported in version 5+

七、参考文章

http://zh.wikipedia.org/wiki/WebSocket

http://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/

http://blog.csdn.net/fenglibing/article/details/7100070

http://www.cnblogs.com/caosiyang/archive/2012/08/14/2637721.html

分析HTML5中WebSocket的原理的更多相关文章

  1. 拾人牙慧篇之——基于HTML5中websocket来实现消息推送功能

    一.写在前面 要求做一个,后台发布信息,前台能即时得到通知的消息推送功能.网上搜了也有很多方式,ajax的定时询问,Comet方式,Server-Sent方式,以及websocket.表示除了定时询问 ...

  2. 带你认识HTML5中的WebSocket

    这篇文章主要介绍了带你认识HTML5中的WebSocket,本文讲解了HTML5 中的 WebSocket API 是个什么东东.HTML5 中的 WebSocket API 的用法.带Socket. ...

  3. HTML5中的WebSocket

    在HTML5规范中,我最喜欢的Web技术就是正迅速变得流行的WebSocket API.WebSocket提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术.这个新的API提供了一个方法 ...

  4. 从虚拟机指令执行的角度分析JAVA中多态的实现原理

    从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...

  5. Python中的浮点数原理与运算分析

    Python中的浮点数原理与运算分析 本文实例讲述了Python中的浮点数原理与运算.分享给大家供大家参考,具体如下: 先看一个违反直觉的例子:     >>> s = 0. > ...

  6. 13万字详细分析JDK中Stream的实现原理

    前提 Stream是JDK1.8中首次引入的,距今已经过去了接近8年时间(JDK1.8正式版是2013年底发布的).Stream的引入一方面极大地简化了某些开发场景,另一方面也可能降低了编码的可读性( ...

  7. 详解HTML5中rel属性的prefetch预加载功能使用

    在HTML5中,有个很有用但常被忽略的特性,就是预先加载(prefetch),它的原理是: 利用浏览器的空闲时间去先下载用户指定需要的内容,然后缓存起来,这样用户下次加载时,就直接从缓存中取出来,效率 ...

  8. 使用HTML5中postMessage实现Ajax中的POST跨域问题

    HTML5中提供了在网页文档之间相互接收与发送信息的功能.使用这个功能,只要获取到网页所在窗口对象的实例,不仅仅同源(域+端口号)的web网页之间可以互相通信,甚至可以实现跨域通信. 浏览器支持程度: ...

  9. WebSocket的原理,以及和Http的关系

    一.WebSocket是HTML5中的协议,支持持久连接:而Http协议不支持持久连接. 首先HTMl5指的是一系列新的API,或者说新规范,新技术.WebSocket是HTML5中新协议.新API. ...

随机推荐

  1. nmon 命令(转)

    转载:https://www.cnblogs.com/kongzhongqijing/articles/4057487.html 一.基本使用 nmon目前可支持AIX和LINUX,可到以下地址去免费 ...

  2. DOS命令:列出某目录下的所有文本文件名并重定向到某文件

    命令如下: >dir /b *.txt>output.txt dir无需说,/b 是只要文件名,>是重定向. 2013年11月7日13:36:57

  3. python xlrd简单读取excel

    import xlrd #打开文件 book = xlrd.open_workbook ('Status.xlsx') #获取数据表 table1 = book.sheets()[0] table2 ...

  4. <c:redirect>标签的使用

    <c:redirect>标签的使用代码例子 redirect.jsp <%@ page contentType="text/html" pageEncoding= ...

  5. Android相机基础基于camera2API

    前言 最近,在使用Android做一个照相机的开发.因为不能使用系统提供的相机应用,所以只能自己写一个.Android以前提供相机的api叫camera,不过在level 21被Google抛弃了.网 ...

  6. hdu 1087 简单dp

    思路和2391一样的.. <span style="font-size:24px;">#include<stdio.h> #include<strin ...

  7. 51CTO 资料汇总 截止20150504

    ================帖子列表,请大家选择自己喜欢的汇总贴分享================ 考试认证: 1.备战2014软考!精品视频教程推荐(综合复习+经验分享+考前冲刺)[随时更新] ...

  8. Pytorch中的norm跟Numpy中的norm对比

  9. Android开发优化之——从代码角度进行优化

    通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻 辑,但是性能不一定是最优化的.一般来说,优秀的程序员在写完代码之后都会不断的对代码进行重构.重构的好处有很多,其中一点, ...

  10. DotNet Core 2.0使用MySql实现Code First

    本教程使用vs2017 + dotnet core2.0 + MySql5.7.19 1.打开vs2017,文件>新建>项目,选择Asp.Net Core Web应用程序. 2.项目名称可 ...