目录结构
 

一、什么是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. [置顶] ArcGIS Runtime SDKs 10.2 for iOS & Android& OS X发布

    我们高兴的宣布:ArcGISRuntime SDKs 10.2 for iOS & Android & OS X正式发布!在10.2版本中,你可以在iOS.Android和Mac设备上 ...

  2. HTML5 <input> required

    要求在提交数据之前必须填写该字段,否则会提交不了   <form>          <input type="text" id="msg" ...

  3. 算法笔记_132:最大流量问题(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 何为最大流量问题? 给定一个有向图,并为每一个顶点设定编号为0~n,现在求取从顶点0(PS:也可以称为源点)到顶点n(PS:也可以称为汇点)后,顶点 ...

  4. java程序设计题库

    选择题 答题要求:单选题,每题只有一个正确答案,选择正确给分,不正确不给分. 1. 下面(   A    )数据类型可用于main()方法中传递的参数 A.String   B.Integer   C ...

  5. vue的全家桶

    自定义指令 <div v-demo="{ color: 'white', text: 'hello!' }"></div> Vue.directive('d ...

  6. ACE中TASK架构简介及简单应用

    一.基础功能介绍 1.ACE_Message_Block*,Windows消息用MSG结构表示,ACE_Task中因为不能预计各种应用中消息的类型,所以ACE_Message_Block基本上可以理解 ...

  7. 【转发】未能加载文件或程序集“Oracle.DataAccess”或它的某一个依赖项。试图加载格式不正确的程序。

     http://www.cnblogs.com/joey0210/archive/2012/09/29/2708420.html   上一篇文章说到了DLL引用问题,主要是说的程序中如果使用过了反射, ...

  8. Java中被你忽视的四种引用(转)

    转载自:http://blog.csdn.net/u010425776/article/details/50760053 Java的数据类型分为两类:基本数据类型.引用数据类型. 基本数据类型的值存储 ...

  9. Tomcat中配置MySQL数据库连接池

    Web开发中与数据库的连接是必不可少的,而数据库连接池技术很好的优化了动态页与数据库的连接,相比单个连接数据库连接池节省了很大的资源.用一个通俗的比喻:如果一个人洗澡需花一桶水,那一百个人就要花一百桶 ...

  10. 【Redis】redis+php处理高并发,很好的教程||附上 php的文件锁

    链接至:http://blog.csdn.net/nuli888/article/details/51865401 很好的教程,其中redis+php有点小问题. 附上php文件锁: $fp = fo ...