HTML5 WebSocket 通讯原理(Java实现)

 在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) 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值