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)

解码函数

 1 function decode($received)
 2       {
 3           $len = $masks = $data = $decoded = null;
 4           $buffer = $received;
 5           $len = ord($buffer[1]) & 127;
 6           if ($len === 126) {
 7               $masks = substr($buffer, 4, 4);
 8               $data  = substr($buffer, 8);
 9           } else {
10               if ($len === 127) {
11                   $masks = substr($buffer, 10, 4);
12                   $data  = substr($buffer, 14);
13               } else {
14                   $masks = substr($buffer, 2, 4);
15                   $data  = substr($buffer, 6);
16               }
17           }
18           for ($index = 0; $index < strlen($data); $index++) {
19               $decoded .= $data[$index] ^ $masks[$index % 4];
20           }
21
22           return $decoded;
23       }

编码函数:

 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 });

效果

时间: 2024-11-06 15:21:28

WebSocket帧数据 解码/转码的相关文章

Android -- 获取摄像头帧数据解码

由于Android下摄像头预览数据只能  ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Parameters p = mCamera.getParameters(); p.setPreviewFormat(ImageFormat.NV21); /*这是唯一值,也可以不设置.有些同学可能设置成 PixelFormat 下面的一个值,其实是不对的,具体的可以看官方文档*/ mCamera.setPa

Android 关于获取摄像头帧数据解码

// 创建保存照片文件夹 private void CreateFileJPG() { File file = new File("/sdcard/image"); if (!file.exists()) { try { file.mkdirs(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } /** * 拍照保存图片 * */ public void saveMyBitmap

TableInputFormat分片及分片数据读取源码级分析

我们在MapReduce中TextInputFormat分片和读取分片数据源码级分析 这篇中以TextInputFormat为例讲解了InputFormat的分片过程以及RecordReader读取分片数据的过程.接下来咱们分析TableInputFormat的分片信息和数据读取过程. TableInputFormat这是专门处理基于HBase的MapReduce的输入数据的格式类.我们可以看看继承结构:(1)public class TableInputFormat extends Table

android获取某应用的帧数据

android获取某应用的帧数据: 说明: (打开手机 开发者选项-GPU显示配置文件(显示于 adb shell dumpsys gfxinfo)勾上,只有4.1以上支持) 在android4.1中,谷歌提供了一个工具来,叫做" GPU呈现模式分析(Profile GPU rendering)", 在开启这个功能后,系统就会记录保留每个界面最后128帧图像绘制的相关时间信息 开始操作: 命令行 adb shell dumpsys gfxinfo com.taobao.mobile.d

USART DMA接送一帧数据(不定长)

内容来源于:http://blog.sina.com.cn/s/blog_777668c30102x4hz.html 1.DMA做所周知这个是好的东西,对于跑裸机的开发者来说是一个福音.但是很多工程师还是按照以前的方式来设计串口,本人看到了真的急的不行.多么好的东西就这样子暴遣天物!可能很多开发者会说DMA是定长的我收发的数据都是不定长的有什么用?如果听到这句话我保证该位同事没有好好研究过DMA.今天把自己DMA不定长发送接收程序贴上来.希望大家在开发的过程少受罪. 2.在大家要开始学习的过程中

H264解码深度解析——DM8168 OMX从H264文件读取一帧数据(do chunking of h264)

源码来源:TI - DM8168 - EZSDK - OMX - examples - decode_display 基本执行流程如下: Decode_GetNextFrameSize(H264_ParsingCtx *pc)函数源码(加注释)如下: /****************************************************************************** Decode_GetNextFrameSize Function Declaration

用libvlc 抓取解码后的帧数据

vlc是一套优秀的开源媒体库,其特点是提供了完整的流媒体框架, 用它可以非常方便的实现抓取解码帧的功能. 与此功能有关的关键API为 libvlc_video_set_callbacks /*设置回调,用来抓取解码后的帧*/ libvlc_video_set_format /*设置解码帧的格式 yuv or rgba ?*/ 这个函数将三个函数指针作为参数 /*callback function, lock the shared memory, and tell vlc where to put

nodejs实现Websocket的数据接收发送

在去年的时候,写过一篇关于websocket的博文:http://www.cnblogs.com/axes/p/3586132.html ,里面主要是借助了nodejs-websocket这个插件,后来还用了socket.io做了些demo,但是,这些都是借助于别人封装好的插件做出来的,websocket到底是怎么实现的呢自己之前真没怎么去想过,最近在看朴灵大神的<深入浅出nodejs>时候,看到websocket那一章,看了一下websocket的数据帧的定义,就琢磨着自己用nodejs来实

Java memcache Client 数据操作源码剖析

 在学习使用Java_Memcache操作memcache后,饶有兴趣的研究了一下Java_Memcache的源码.Java_Memcache在类AscIIClient中封装了数据操作方法set/add/delete/append/get等. 存储数据set 由Memcache命令详解,我们知道memcache原始的set命令格式为 set <key> <flag> <expiretime> <bytes> \r\n <value> \r\n