现在的位置: 首页 > 综合 > 正文

实现Draft-17的WebSocket之体会篇

2013年09月21日 ⁄ 综合 ⁄ 共 2340字 ⁄ 字号 评论关闭

     

       HTML5的其中一个特色是WebSocket,WebSocket的标准一直没有定稿,IE,FF,Chrome和Safari实现有所不同,IE9,FF8暂时不能实现WebSocket标准,Safari实现的是Draft-76,该草案已经过期,Chrome能够实现最新版的Draft-17,俺就尝试实现一个简单的信息传输和回应练习一下。

      传递信息之前首先要浏览器和服务器实现handshakes,Chrome浏览器发送一个这样的HTTP头:

 

     Get  socket/client/client.php  HTTP/1.1

  1. Connection:
    Upgrade
  2. Host:
    192.168.1.102:8160
  3. Sec-WebSocket-Key:
    JJ+5PGCsOydngWBY3axAEA==
  4. Sec-WebSocket-Origin:
    http://192.168.1.102:8150
  5. Sec-WebSocket-Version:
    8
  6. Upgrade:
    websocket

 

     服务器回应:

     HTTP/1.1 101 Switching Protocols    

  1. Connection:
    Upgrade
  2. Sec-WebSocket-Accept:
    EC83XYnK0G//n7ZrrFE8c6XOQVY=
  3. Upgrade:
    WebSocket
  4. WebSocket-Location:
    ws://192.168.1.102:8160/socket/server/startDaemon.php
  5. WebSocket-Origin:

 

     其他都没有什么,就是注意Sec-WebSocket-Key和Sec-WebSocket-Accept信息,他们是handshakes成功的关键

     Sec-WebSocket-Accept码是根据Sec-WebSocket-Key计算出来的,步骤如下:

     1.取出Sec-WebSocket-Key,与一个magic string “258EAFA5-E914-47DA-95CA-C5AB0DC85B11” 连接成一个新的key串,如JJ+5PGCsOydngWBY3axAEA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11;

   2.将新的key串SHA1编码,生成一个由多组两位16进制数构成的加密串;

   3.把加密串按2位16进制数字分隔,进行base64编码生成最终的key如:EC83XYnK0G//n7ZrrFE8c6XOQVY=

   4.将这个key作为Sec-WebSocket-Accept;

   PHP实现的话,就是这样:

   $acceptkey = base64_encode ( sha1 ( $SecWebSocketKey . $magickey, true ) )

   一句话

 

    如果握手成功,Chrome浏览器的WebSocket对象响应onopen事件,WebSocket对象是Chrome浏览器内置对象,如果关闭,onclose事件响应,收到正确信息onmessage事件响应,还有一个状态属性,readyState表示当前状态。

 

    下面说说如何发送数据:

    根据Draft-17草案,实现数据速递要比Draft-76草案复杂,以下以发送小于125字节数据为例,因为最大125字节,所以一个帧就可装完,如Chrome浏览器发送Hello:

    Chrome浏览器要发送UTF-8数据的第一个字节为0x81,Hello长度是5位字符,第二个要发送字节是0x80(加密flag)加上Hello长度,所以为0x85,接着是4个字节MaskKey,和加密的

5字节Hello,如:

   

    发送大于125字节,这里不讲。

    服务器如何取出“hello”,是这样的,第一个maskkey与第一个payload异或运算,第二个maskkey与第二个payload异或运算...第四个maskkey与第四个payload异或运算,第一个maskkey与第五个payload异或运算,如此循环,直到最后一个payload,

    PHP这样实现:

    $Paylen为实际负载长度,这里就是5;

    $date_bytes为整个数据字段,如上图蓝色底纹;

    if ($Paylen<126) {
     for ($i = 0; $i <= 3; $i++) {
      $mask[]=$date_bytes[2+$i];
     }
     $payload_start = 6;
     $date_lenth=count($date_bytes);
     for ($i = $payload_start; $i < $date_lenth; $i++) {
       $payload[]=$mask[($i - $payload_start) % 4]^$date_bytes[$i];     
     }

     $payload[]=hello;

   

    服务器响应返回数据hello, how are you?到Chrome浏览器,发送UTF-8数据的第一个字节仍然是为0x81,第二个字节为返回数据的长度,即使hello, how are you?字符串长度ox13(十进制19),随后是不加密的有效字符串,如下图:

   

   

   Chrome浏览器收到这个信息就会有onmessage事件,Javascropt脚本:

   Websocket.onmessage = function(msg){ log("Received: "+msg.data); };

  

   测试结果:

   

 

图二:

 

抱歉!评论已关闭.