数据从浏览器通过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;
}

  

编码函数:

 function encode($buffer)
{
$len = strlen($buffer); $first_byte = self::BINARY_TYPE_BLOB; if ($len <= 125) {
$encode_buffer = $first_byte . chr($len) . $buffer;
} else {
if ($len <= 65535) {
$encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer;
} else {
//pack("xxxN", $len)pack函数只处理2的32次方大小的文件,实际上2的32次方已经4G了。
$encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer;
}
} return $encode_buffer;
}
}

服务器端代码:

 <?php 

   class WebSocket
{
const BINARY_TYPE_BLOB = "\x81";
private $socket; public function __construct($port)
{
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $port);
socket_listen($socket);
return $this ->socket = $socket;
} public function run()
{
$clients[] = $this -> socket;
while(true)
{
$read = $clients;
$write = null;
$except = null;
if(false === socket_select($read, $write, $except, null))
{
continue;
} if(in_array($this -> socket, $read))
{
echo "new request ...\n";
$clients[] = $newsock = socket_accept($this -> socket);
$request = socket_read($newsock, 321600*2);
if($this -> handshake($newsock, $request))
{
socket_getpeername($newsock, $ip);
echo "new client $ip conntected\n";
$key = array_search($this -> socket, $read);
unset($read[$key]);
}
else
{
echo "handshake failed \n";
}
} foreach ($read as $sock_read)
{
$data = socket_read($sock_read, 32160*2);
if(false === $data)
{
$key = array_search($sock_read, $clients);
socket_getpeername($clients[$key], $ip);
unset($clients[$key]);
echo "client $ip disconnected\n";
continue;
}
$data = $this -> decode($data);
$response = "recevied data len : ".strlen($data)." $data";
$response = $this -> encode($response);
socket_write($sock_read, $response, strlen($response));
}
}
socket_close($this -> socket);
} public function handshake($socket, $request)
{
if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $request, $match)) {
$Sec_WebSocket_Key = $match[1];
}
// Calculation websocket key.
$new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
// Handshake response data.
$handshake_message = "HTTP/1.1 101 Switching Protocols\r\n";
$handshake_message .= "Upgrade: websocket\r\n";
$handshake_message .= "Sec-WebSocket-Version: 13\r\n";
$handshake_message .= "Connection: Upgrade\r\n";
$handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; socket_write($socket, $handshake_message); return true;
} public 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;
} public function encode($buffer)
{
$len = strlen($buffer); $first_byte = self::BINARY_TYPE_BLOB; if ($len <= 125) {
$encode_buffer = $first_byte . chr($len) . $buffer;
} else {
if ($len <= 65535) {
$encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer;
} else {
//pack("xxxN", $len)pack函数只处理2的32次方大小的文件,实际上2的32次方已经4G了。
$encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer;
}
} return $encode_buffer;
}
} $ws = new WebSocket(1313);
$ws -> run();

客户端代码:

 $(function(){
url = "ws://localhost:1313/server.php";
socket = new WebSocket(url);
cnt = 1; socket.onopen = function()
{
socket.send("this is chrome broswer");
} socket.onmessage = function(msg)
{
$('#info').append(msg.data);
}
});

效果

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

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

    由于Android下摄像头预览数据只能  ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...

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

    由于Android下摄像头预览数据只能  ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...

  3. FFmpeg(7)-av_read_frame()读取帧数据AVPacket和av_seek_frame()改变播放进度

    一.av_read_frame() 该函数用于读取具体的音/视频帧数据 int av_read_frame(AVFormatContext *s, AVPacket *pkt); 参数说明: AVFo ...

  4. Python+moviepy音视频剪辑:视频帧数据的本质、Clip的fl方法进行变换处理的原理以及滚屏案例

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一. ...

  5. 项目一:第五天 1、区域数据(pinyin4j-简码,城市编码) 2、Web层代码重构(model对象,分页代码提取) 3、区域分页查询 3、分区添加功能 4、定区管理管理-添加,分页

    Service: /** * @Description: 1.保存定区  2.让分区关联定区 * 对象三种状态 1.持久态(被session管理对象-一级缓存中有对象) 2.托管态(有OID标识,数据 ...

  6. stm32 USART_IT_IDLE中断 一帧数据

    USART_IT_IDLE中断,是串口收到一帧数据后,发生的中断.也可以叫做一包数据 USART_IT_IDLE和USART_IT_RXNE区别 当接收到1个字节,会产生USART_IT_RXNE中断 ...

  7. Soul 网关 Nacos 数据同步源码解析

    学习目标: 学习Soul 网关 Nacos 数据同步源码解析 学习内容: 环境配置 Soul 网关 Nacos 数据同步基本概念 源码分析 学习时间:2020年1月28号 早7点 学习产出: 环境配置 ...

  8. 用libvlc 抓取解码后的帧数据

    vlc是一套优秀的开源媒体库,其特点是提供了完整的流媒体框架, 用它可以非常方便的实现抓取解码帧的功能. 与此功能有关的关键API为 libvlc_video_set_callbacks /*设置回调 ...

  9. nodejs实现Websocket的数据接收发送

    在去年的时候,写过一篇关于websocket的博文:http://www.cnblogs.com/axes/p/3586132.html ,里面主要是借助了nodejs-websocket这个插件,后 ...

随机推荐

  1. Linux 中 17 个 tar 命令实用示例

    Tar(Tape ARchive,磁带归档的缩写,LCTT 译注:最初设计用于将文件打包到磁带上,现在我们大都使用它来实现备份某个分区或者某些重要的目录)是类 Unix 系统中使用最广泛的命令,用于归 ...

  2. BZOJ3697: 采药人的路径

    传送门 不是那么裸的点分治. $f[i][0/1]$表示当前节点的一个子树中总权值和为$i$,且是否存在一个前缀使得其前缀和为$i$ $g[i][0/1]$表示当前节点的已遍历过的子树,其余一样. 对 ...

  3. photoshop切图介绍

    第一部分:界面设置 1.点击“文件-新建”(或者ctrl+n)打开一个新建对话框.名称可随意填写.“预设”设置为自定,“宽度”一般选择1920,“单位”选为像素.“高度”可选择为2000,“单位”选为 ...

  4. 【原】react中如何使用jquery插件

    react的思想是虚拟dom,提倡最好较少dom的操作,可是我们在写网页的时候,有些复杂的交互还是离不开jquery插件的.而且当你把jquery直接拿来用的时候,你会发觉会报错,要么是找不到那个插件 ...

  5. PHP 数组(遍历)

    数组定义$attr = array(); //定义一个空的数组$attr = array(1,2,3,4); //定义一个有值的数组$attr[0]="aa";$attr[1]=& ...

  6. Python学习之模块进程函数详解

    今天在看<Beginning Linux Programming>中的进程相关部分,讲到Linux几个进程相关的系统函数: system , exec , fork ,wait . Pyt ...

  7. windows 修改hosts 脚本

    @echo off echo "请注意你的杀毒软件提示,一定要允许" echo. & pause @del C:\Windows\System32\drivers\etc\ ...

  8. JavaWeb学习笔记——表达式语言

    使用表达式语言,可以方便地访问标志位(JSP中有page(pageContext).request.session和application4种标志位)中的属性内容,可以避免出现许多的Scriptlet ...

  9. Java——单选按钮:JRadioButton

    import java.awt.Container; import java.awt.GridLayout; import java.awt.event.WindowAdapter; import j ...

  10. 关于Linux发行版的选择

    Linux发行版很多,分为以RedHat为代表的商业发行版和以Debian为代表的免费发行版.前者典型版本有CentOS.Fedora.SUSE等,后者的典型版本有Ubuntu等 CentOS.Ubu ...