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;
}
编码函数:
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帧数据 解码/转码的更多相关文章
- Android -- 获取摄像头帧数据解码
由于Android下摄像头预览数据只能 ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...
- Android 关于获取摄像头帧数据解码
由于Android下摄像头预览数据只能 ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...
- FFmpeg(7)-av_read_frame()读取帧数据AVPacket和av_seek_frame()改变播放进度
一.av_read_frame() 该函数用于读取具体的音/视频帧数据 int av_read_frame(AVFormatContext *s, AVPacket *pkt); 参数说明: AVFo ...
- Python+moviepy音视频剪辑:视频帧数据的本质、Clip的fl方法进行变换处理的原理以及滚屏案例
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一. ...
- 项目一:第五天 1、区域数据(pinyin4j-简码,城市编码) 2、Web层代码重构(model对象,分页代码提取) 3、区域分页查询 3、分区添加功能 4、定区管理管理-添加,分页
Service: /** * @Description: 1.保存定区 2.让分区关联定区 * 对象三种状态 1.持久态(被session管理对象-一级缓存中有对象) 2.托管态(有OID标识,数据 ...
- stm32 USART_IT_IDLE中断 一帧数据
USART_IT_IDLE中断,是串口收到一帧数据后,发生的中断.也可以叫做一包数据 USART_IT_IDLE和USART_IT_RXNE区别 当接收到1个字节,会产生USART_IT_RXNE中断 ...
- Soul 网关 Nacos 数据同步源码解析
学习目标: 学习Soul 网关 Nacos 数据同步源码解析 学习内容: 环境配置 Soul 网关 Nacos 数据同步基本概念 源码分析 学习时间:2020年1月28号 早7点 学习产出: 环境配置 ...
- 用libvlc 抓取解码后的帧数据
vlc是一套优秀的开源媒体库,其特点是提供了完整的流媒体框架, 用它可以非常方便的实现抓取解码帧的功能. 与此功能有关的关键API为 libvlc_video_set_callbacks /*设置回调 ...
- nodejs实现Websocket的数据接收发送
在去年的时候,写过一篇关于websocket的博文:http://www.cnblogs.com/axes/p/3586132.html ,里面主要是借助了nodejs-websocket这个插件,后 ...
随机推荐
- XML学习笔记
XML学习笔记 第一部分:XML简介 我们经常可以听到XML.HTML.XHTML这些语言,后两者比较清楚,一直不是很明白XML是什么,这里做一个总结. XML(eXtensible Markup L ...
- linux安装ftp组件
1 安装vsftpd组件 linux系统安装完后,有/etc/vsftpd/vsftpd.conf 文件,是vsftp的配置文件. [root@bogon ~]# yum -y install v ...
- java编程思想-java 异常使用指南
应该在以下情况下使用异常: 在恰当的级别处理问题(在知道该如何处理的情况下才捕获异常). 解决问题并且重新调用产生异常的方法. 进行少许修补,然后绕过异常发生的地方继续执行. 用别的数据进行计算,以代 ...
- IOS 中的CoreImage框架(framework)
http://www.cnblogs.com/try2do-neo/p/3601546.html coreimage framework 组成 apple 已经帮我们把image的处理分类好,来看看它 ...
- Centos: 修改 yum安装的mysql路径
1.使用命令service mysqld stop 停止mysql查看mysql数据库的默认路径:/var/lib/mysql使用cp -afir /var/lib/mysql/* /usr/l ...
- Java数据结构——用双端链表实现队列
//================================================= // File Name : LinkQueue_demo //---------------- ...
- 监控web页面的性能指标。
监控一个web页面的性能也是非常重要的,h5提供了一个非常好的属性来监控: window.performance 它有两个成员: navigation (一个叫做performanceNavi ...
- SDK
IOS: iOS Application Life Cycle 应用程序生命周期 http://www.cnblogs.com/chenyg32/p/3873301.html iOS应用程序生命周期( ...
- python sys os hashlib_MD5 模块
模块 内置模块是Python自带的功能,在使用内置模块相应的功能时,需要[先导入]再[使用] 一.sys 用于提供对Python解释器相关的操作: ? 1 2 3 4 5 6 7 8 9 sys.ar ...
- jqxTreeGrid
基本TreeGrid样本 <!DOCTYPE html> <html lang="en"> <head> <title id=" ...