HTML5 WebSocket 通讯原理.(Java实现,附件源码)
DaN_DaN
2011-09-11
在javaeye都好久了.但是从来没发表个什么东西
由于最近在观注 HTML5 于是就看了下WebSocket 又不想找现成的框架去搞.就打算自己弄弄. 开始吧. 提前条件 1> 了解socket. 2> 了解协议,了解HTTP协议更好.(想想为什么需要协议就行.安全?保证数据完整?便于解析?) 3> 理解字节,字节序,如: 32位int 的 30转成 高字节序的字节 及是 0x00 0x00 0x00 0x1E,低字节序则 0x1E 0x00 0x00 0x00. 没数错的话是4个字节^_^ Web Socket参考文章 1. http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 因为感觉里面有点乱,顺序没有按常理出牌. 下面是按我觉得应该有的顺序截取了该文章关键部分 The following diagrams summarise the protocol: Handshake | V Frame type byte <-------------------------------------. | | | | `-- (0x00 to 0x7F) --> Data... --> 0xFF -->-+ | | `-- (0x80 to 0xFF) --> Length --> Data... ------->-' 一个 WebSocket 通讯流程 简单说.就是先握手.在谈话.(跟见到领导一样) Internet-Draft The WebSocket protocol August 2010 /*请求部分也就是浏览器传到服务器的数据,需要解析*/ GET /demo HTTP/1.1 Host: example.com Connection: Upgrade Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Sec-WebSocket-Protocol: sample Upgrade: WebSocket Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5 Origin: http://example.com ^n:ds[4U The handshake from the server looks as follows: /*响应部分 需要根据 请求消息 来生成响应报文*/ HTTP/1.1 101 WebSocket Protocol Handshake Upgrade: WebSocket Connection: Upgrade Sec-WebSocket-Origin: http://example.com Sec-WebSocket-Location: ws://example.com/demo Sec-WebSocket-Protocol: sample 8jKS'y:G*Co,Wxa- //上面request/response部分的以第二行至倒数第三行 都是这种格式,并且顺序无关 After the leading line in both cases come an unordered ASCII case- insensitive set of fields, one per line, that each match the following non-normative ABNF: [RFC5234] field = 1*name-char colon [ space ] *any-char cr lf colon = %x003A ; U+003A COLON (:) space = %x0020 ; U+0020 SPACE cr = %x000D ; U+000D CARRIAGE RETURN (CR) lf = %x000A ; U+000A LINE FEED (LF) name-char = %x0000-0009 / %x000B-000C / %x000E-0039 / %x003B-10FFFF ; a Unicode character other than U+000A LINE FEED (LF), U+000D CARRIAGE RETURN (CR), or U+003A COLON (:) any-char = %x0000-0009 / %x000B-000C / %x000E-10FFFF ; a Unicode character other than U+000A LINE FEED (LF) or U+000D CARRIAGE RETURN (CR) NOTE: The character set for the above ABNF is Unicode. The fields themselves are encoded as UTF-8. Lines that don't match the above production cause the connection to be aborted. /****************重点部分******************/ To prove that the handshake was received, the server has to take three pieces of information and combine them to form a response. The first two pieces of information come from the |Sec-WebSocket-Key1| and |Sec-WebSocket-Key2| fields in the client handshake: 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. with 0x0D 0x0A and followed by 8 random bytes, part of a challenge, and the server sends 18 bytes starting with 0x0D 0x0A and followed by 16 bytes consisting of a challenge response. The details of this challenge and other parts of the handshake are described in the next section. The concatenation of the number obtained from processing the |Sec- WebSocket-Key1| field, expressed as a big-endian 32 bit number, the number obtained from processing the |Sec-WebSocket-Key2| field, again expressed as a big-endian 32 bit number, and finally the eight bytes at the end of the handshake, form a 128 bit string whose MD5 sum is then used by the server to prove that it read the handshake. 大概意思就是说 服务端需要根据 Sec-WebSocket-Key1,Sec-WebSocket-Key2和请求响应部分的最后8个字节 生成一个16个字节的数组(128位) 再对他进行MD5 签名 也就是 响应消息最后的 8jKS'y:G*Co,Wxa- 实际上是根据 Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5 ^n:ds[4U //请求响应部分的最后8个字节 计算出来的 规则: 将的key1值部分"4 @1 46546xW%0l 1 5" 取掉非数字的字符,会得到一个数字 则: 414654015 在计算该字符串的空格数 假设为 n 让 int key1 = (414654015 / n); 然后将他转成 高字节序的字节数组 伪代码: public byte[] formatKey(String key); main { byte[] bytes = new byte[16]; bytes[0~3] = formatKey(key1); bytes[4~7] = formatKey(key2); bytes[8~15] = 请求响应部分的最后8个字节 bytes = md5(bytes); } /***********************************************/ 接下来的就简单了===发消息 This wire format for the data transfer part is described by the following non-normative ABNF, which is given in two alternative forms: the first describing the wire format as allowed by this specification, and the second describing how an arbitrary bytestream would be parsed. [RFC5234] //大概意思就是说有两种数据通讯协议,第一种简单的文本,也就是源码里用的,第二种就是二进制数据通讯协议.. ****传输之前必须先握手**** ; the wire protocol as allowed by this specification frames = *frame frame = text-frame text-frame = (%x00) *( UTF8-char ) %xFF ; the wire protocol including error-handling and forward-compatible parsing rules frames = *frame frame = text-frame / binary-frame text-frame = (%x00-%x7F) *( UTF8-char / %x80-%x7E ) %xFF binary-frame = (%x80-%xFF) length < as many bytes as given by the length > length = *(%x80-%xFF) (%x00-%x7F) 遵循他的格式. 照着socket 收发消息那样发就OK了! 如:发一个 Hello! byte[] data = new byte[2+]; byte[0] = 0x00 byte[1~data.length - 1] = "Hello!".getBytes("UTF-8"); byte[data.length - 1] = 0xFF //源码运行方式 1.WebServerSocket.main(); 2.打开 socket.html (用Google Chrome) 我的环境: WindowsXP,JDK1.6 , Google Chrome(version 13.0.782.220 m) 第一次写技术性的文章。希望大家喜欢,多多指教 ^_^. 此文章带有附件,请前往http://www.iteye.com/topic/1114602下载 |
|
KimHo
2011-09-13
说下背景和应用场景,看得一头雾水,呵呵
|
|
shenliu
2011-09-13
DaN_DaN 写道 提前条件
1> 了解socket. 2> 了解协议,了解HTTP协议更好.(想想为什么需要协议就行.安全?保证数据完整?便于解析?) 3> 理解字节,字节序,如: 32位int 的 30转成 高字节序的字节 及是 0x00 0x00 0x00 0x1E,低字节序则 0x1E 0x00 0x00 0x00. 没数错的话是4个字节^_^ 请楼主给出上面各项的参考,谢谢~~ |
|
rainsilence
2011-09-13
主要内容:
1.得到报文,注意是以/r/n/r/n结尾,在结尾后还有8个byte,要记录下来。 2.对报文中的两个key,先数空格数,在去掉非数字后得到一个数,用数字/空格数,并对他进行高位byte。组合刚才的8个byte进行md5签名 3.回发客户端。即可完成握手 4.在消息发送时,以0x00开头,以0xFF结尾 主要是协议解析比较麻烦。 |
|
rainsilence
2011-09-13
知道这个原理,加上canvas或者webgl,国人就可以写出自己的大型网页游戏。比如cs版的魔兽争霸,cs等。
|
|
CurrentJ
2011-09-13
rainsilence 写道 知道这个原理,加上canvas或者webgl,国人就可以写出自己的大型网页游戏。比如cs版的魔兽争霸,cs等。 webserver不就是干这个的么? |
|
LeoChowComtop
2011-09-13
. 楼主需要加固下基础知识
|
|
rainsilence
2011-09-13
CurrentJ 写道 rainsilence 写道 知道这个原理,加上canvas或者webgl,国人就可以写出自己的大型网页游戏。比如cs版的魔兽争霸,cs等。
webserver不就是干这个的么? 现在的主流webserver只支持http协议,而不支持ws协议。lz所干的事情就是解析了ws协议。 |
|
rainsilence
2011-09-13
LeoChowComtop 写道 . 楼主需要加固下基础知识
代码里面,特别是思想层面,确实有不少不到位的地方。但更多的是写的出彩的地方。作为一个仅仅说明原理的sample来说,这绝对已经足够了。国外在一年前就有人模拟了websocket服务器端,但是这一年以来,就没有国人有这样的技术敏感度。像lz这样肯钻研的人已经很少了,应该鼓励而不应该打压。 |
|
maskainv
2011-09-13
试了一下 确实可以与后台交互。
哎 一年以前我也想用WebServerSocket做一个前后台即时交互的小demo的。当时我的想法是用struts结合这个一起写。在网上找了好多,有外国人用PHP实现的。可惜俺不会玩那玩意啊。又有人说用jetty7可以实现,跑去看看源码。下了的demo感觉还是搞不定啊。后面就放弃了。自愧不如啊~~~ |