一起来用Websocket(二):Websocket协议详细分析
前言
本节主要翻译一下websocket的协议。其中,socket通信开发,最重要的就是协议了。通信软件(QQ、MSN)、杀毒软件(360、金山)、电信软件(短信、通话)等行业软件有自己的协议。有了协议,我们可以无视语言和平台,使得大家都可以为这个平台做开发,就像我们用了同一种语言,同一个电波一样。总的来说,在通信程序开发中,协议成为了分步式处理、跨平台、跨语言的重要作用,在websocket中也不例外。
协议分很多种,OSI的七层协议,如果现在记得不清楚的也没关系。在开发中,我们几乎只需了解TCP协议就行了,这里由于篇幅原因,也不对整编websocket协议进行整篇翻译。只对其中的几点需注意的地方进行一个说明吧。
注1:This Internet-Draft will expire on November 7, 2010.
P2 本篇过期时间为到2010年11月7日。这个应该不准,这个要浏览器的支持了,像Filefox4.0才会完全支持html5,如果你使用Chrome,那么也跟你得到的版本有关。不是那么特别的。
注2:A simpler solution would be to use a single TCP connection for traffic in both directions
websocket是一种基于一个TCP连接的全双工的通讯方式,也就是说,服务端可以主动推数据到客户端,客户端也可以发送数据到服务端。
注3:1.2. Protocol overview
The handshake from the client looks as follows:[省去协议内容]
The handshake from the server looks as follows:[省去协议内容]
在webcoket中,是由客户端先发送请求头信息到服务端,服务端对请求进行检查,如果是合法的请求头,则会发送握手信息到客户端。同是为每个客户端建产一个socket用来通信。这个socket有输入流,也有输出流,是一个全双工的tcp通信端口。
其中客户端的请求头和服务端的握手信息都是每行一个的键值对信息,且字符编码为ASCII 编码。这个很重要,因为在传送数据的时候,是以utf8做编码的。
注4:1.3 Opening handshake
建产握手。这个是整个websocket协议中最重要的一个环节。因为握手是建立连接,或进行下一步通信的关键,也是关系到你是否能和其它遵寻html5 websocket协议的浏览器(如chrome,fiirfox4.0等)进行通信的关键。
下面主要讲一点比较不容易计算的的地方。
Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8
Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0
For each of these fields, the server has to take the digits from the
value to obtain a number (in this case 1868545188 and 1733470270
respectively), then divide that number by the number of spaces
characters in the value (in this case 12 and 10) to obtain a 32-bit
number (155712099 and 173347027). These two resulting numbers are
then used in the server handshake, as described below.
这里的两个key值,分别代表两个数。把上面的两个字符数数组转化成字符串后,变成了1868545188和1733470270。然后,再查看这两个key中空格字符的个数。
第一个key一共有12个空格。所以1868545188/12=155712099.同理,第二个key一共有10个空格1733470270/10=173347027
注5:P6 Data is sent in the form of UTF-8 text. Each frame of data starts with a 0x00 byte and ends with a 0xFF byte, with the UTF-8 text in between….
当握手成功后,就是进行数据传送了。注意 ,这个时候tcp连接已在经建立了,现在客户发送上来的时候就是纯纯的数据了。服务端要判断什么时候是一次数据请求的开始,什么时候是请求的结束。这个也要是处理在tcp发送中的黏包的问题。由于在tcp协议中,会存在两个缓冲区去存放发送的数据或接收的数据,如果没有显的分割符则会让服务端无法正确的识别两条命令。
在websocket中,由于浏览端和服务端已经打好招呼,我发送的内容为utf-8 编码,如果我发送0x00,表是是一条命令的开始,如果发磅了0xFF,就表示这条命令已经结束了。这样就可以在浏览器的配合下很好解决上面黏包的问题。
也可由下图所示:
Handshake
|
V
Frame type byte <--------------------------------------.
| | |
| `--> (0x00 to 0x7F) --> Data... --> 0xFF -->-+
| |
`--> (0x80 to 0xFE) --> Length --> Data... ------->-'
注6: P8 The |Origin| field is used to protect against unauthorized cross-
origin use of a WebSocket server by scripts using the |WebSocket| API
in a Web browser. The server specifies which origin it is willing to
receive requests from by including a |Sec-WebSocket-Origin| field
with that origin. If multiple origins are authorized, the server
echoes the value in the |Origin| field of the client's handshake.
请求中的Origin字段,可以用来做身份验证的作用,如果使用得当,可以减少非法来源的连接建产。可以结合SEC-websocket-Origin来使用。其次,在请求中,还会伴随传过来头信息的md5码,可以起到防篡改的作用,可以进一步增强安全性验证。其实,还有一招,就算连接已经建立,我们还可以通过让客户端请求用户名和密码的方式使用业务逻辑再经过一次验证。
注7:P10 1.4 Cloing handshake
每个端只要向另一端口发送一个0xFF的信息,就表示连接已结束了。这个相关于tcp/ip协议中的fin/ack.
注8: 1.5 Design philosophy
这节是非正式的,但是作者有提到,websocket是可以和http共用监听端口的,以后也可能会扩展协议,由于现在传送的是字符串,后期可能会追求更好的压缩率,采用二进制传送。
其实,我们用现的协议开发时,也可以在发送的时候把数据压缩,在接收的时候把数据解压缩。
注9:3.1 Parsing websoket URLS
If the /secure/ flag is false, then append the string "ws://" to
/url/. Otherwise, append the string "wss://" to /url/.
处理websocket链接。服务端只会去识别ws://或wss://开头的请求,这样的话,就不会和其它的监听服务进行冲突出了吧。
注:客户端发送的请求中,服务端地址为wss://www.example.com:8787/im?id=123456
那么www.example.com是服务端的地址,监听的端口号为8787,im是对应的请求名称,其中传送的参数为id,值为123456.
注10 :4 Client-side requirements
这章主要是以客户端(浏览器)为中心。所以一切的主语都是客户端。详细讲了客户端发送请求头和数据信息的内容。
注11 :5 Server-Side requirements
这章主要是以服务端(监听服务)为中心,详细服务端如何处理请求和处理握手的过程。
引用:原文链接:http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76