WebSocket幀數據 解碼/轉碼


數據從瀏覽器通過websocket發送給服務器的數據,是原始的幀數據,默認是被掩碼處理過的,所以需要對其利用掩碼進行解碼。

從服務器發送給瀏覽器的數據是默認沒有掩碼處理的,只要符合一定結構就可以了。具體可以參考websocket的RFC文檔

http://www.rfcreader.com/#rfc6455

The threat model being protected against is one in which the client sends data that appears to be an HTTP request. As such, the channel that needs to be masked is the data from the client to the server. The data from the server to the client can be made to look like a response, but to accomplish this request, the client must also be able to forge a request. As such, it was not deemed necessary to mask data in both directions (the data from the server to the client is not masked)

解碼函數

 

function decode($received)
      {
          $len = $masks = $data = $decoded = null;
          $buffer = $received;
          $len = ord($buffer[1]) & 127;
          if ($len === 126) {
              $masks = substr($buffer, 4, 4);
              $data  = substr($buffer, 8);
          } else {
              if ($len === 127) {
                  $masks = substr($buffer, 10, 4);
                  $data  = substr($buffer, 14);
              } else {
                  $masks = substr($buffer, 2, 4);
                  $data  = substr($buffer, 6);
              }
          }
          for ($index = 0; $index < strlen($data); $index++) {
              $decoded .= $data[$index] ^ $masks[$index % 4];
          }

          return $decoded;
      }

  

編碼函數:

 1 function encode($buffer)
 2       {
 3           $len = strlen($buffer);
 4 
 5           $first_byte = self::BINARY_TYPE_BLOB;
 6 
 7           if ($len <= 125) {
 8               $encode_buffer = $first_byte . chr($len) . $buffer;
 9           } else {
10               if ($len <= 65535) {
11                   $encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer;
12               } else {
13                 //pack("xxxN", $len)pack函數只處理2的32次方大小的文件,實際上2的32次方已經4G了。 
14                   $encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer;
15               }
16           }
17 
18           return $encode_buffer;
19       }
20   }

服務器端代碼:

  1 <?php 
  2   
  3   class WebSocket
  4   {
  5       const BINARY_TYPE_BLOB = "\x81";
  6       private $socket;
  7 
  8       public function __construct($port)
  9       {
 10           $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
 11           socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
 12           socket_bind($socket, 0, $port);
 13           socket_listen($socket);
 14           return $this ->socket = $socket;
 15       }
 16 
 17       public function run()
 18       {
 19           $clients[] = $this -> socket;
 20           while(true)
 21           {
 22               $read = $clients;
 23               $write = null;
 24               $except = null;
 25               if(false === socket_select($read, $write, $except, null))
 26               {
 27                   continue;
 28               }
 29 
 30               if(in_array($this -> socket, $read))
 31               {
 32                   echo "new request ...\n";
 33                   $clients[] = $newsock = socket_accept($this -> socket);
 34                   $request = socket_read($newsock, 321600*2);
 35                   if($this -> handshake($newsock, $request))
 36                   {
 37                       socket_getpeername($newsock, $ip);
 38                       echo "new client $ip conntected\n";
 39                       $key = array_search($this -> socket, $read);
 40                       unset($read[$key]);
 41                   }
 42                   else
 43                   {
 44                       echo "handshake failed \n";
 45                   }
 46               }
 47 
 48               foreach ($read as $sock_read)
 49               {
 50                   $data = socket_read($sock_read, 32160*2);
 51                   if(false === $data)
 52                   {
 53                       $key = array_search($sock_read, $clients);
 54                       socket_getpeername($clients[$key], $ip);
 55                       unset($clients[$key]);
 56                       echo "client $ip disconnected\n";
 57                       continue;
 58                   }
 59                   $data = $this -> decode($data);
 60                   $response = "recevied data len : ".strlen($data)." $data";
 61                   $response = $this -> encode($response);
 62                   socket_write($sock_read, $response, strlen($response));
 63               }
 64           }
 65           socket_close($this -> socket);
 66       }
 67 
 68       public function handshake($socket, $request)
 69       {
 70             if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $request, $match)) {
 71                 $Sec_WebSocket_Key = $match[1];
 72             } 
 73             // Calculation websocket key.
 74             $new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
 75             // Handshake response data.
 76             $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n";
 77             $handshake_message .= "Upgrade: websocket\r\n";
 78             $handshake_message .= "Sec-WebSocket-Version: 13\r\n";
 79             $handshake_message .= "Connection: Upgrade\r\n";
 80             $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
 81 
 82             socket_write($socket, $handshake_message);
 83 
 84             return true;
 85       }
 86 
 87       public function decode($received)
 88       {
 89           $len = $masks = $data = $decoded = null;
 90           $buffer = $received;
 91           $len = ord($buffer[1]) & 127;
 92           if ($len === 126) {
 93               $masks = substr($buffer, 4, 4);
 94               $data  = substr($buffer, 8);
 95           } else {
 96               if ($len === 127) {
 97                   $masks = substr($buffer, 10, 4);
 98                   $data  = substr($buffer, 14);
 99               } else {
100                   $masks = substr($buffer, 2, 4);
101                   $data  = substr($buffer, 6);
102               }
103           }
104           for ($index = 0; $index < strlen($data); $index++) {
105               $decoded .= $data[$index] ^ $masks[$index % 4];
106           }
107 
108           return $decoded;
109       }
110 
111       public function encode($buffer)
112       {
113           $len = strlen($buffer);
114 
115           $first_byte = self::BINARY_TYPE_BLOB;
116 
117           if ($len <= 125) {
118               $encode_buffer = $first_byte . chr($len) . $buffer;
119           } else {
120               if ($len <= 65535) {
121                   $encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer;
122               } else {
123                 //pack("xxxN", $len)pack函數只處理2的32次方大小的文件,實際上2的32次方已經4G了。 
124                   $encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer;
125               }
126           }
127 
128           return $encode_buffer;
129       }
130   }
131 
132   $ws = new WebSocket(1313);
133   $ws -> run();

客戶端代碼:

 1 $(function(){
 2     url = "ws://localhost:1313/server.php";
 3     socket = new WebSocket(url);
 4     cnt = 1;
 5 
 6     socket.onopen = function()
 7     {
 8         socket.send("this is chrome broswer");
 9     }
10 
11     socket.onmessage = function(msg)
12     {
13         $('#info').append(msg.data);
14     }
15 });

效果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM