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这个插件,后 ...
随机推荐
- Hierarchical Softmax
When predicting over large vocabulary, softmax becomes one of the expensive computation part. There ...
- JBoss AS7 快速配置
作者:MinUnix 原文出处:http://www.minunix.com/2013/08/jboss-as7-01/ 如需转载请注明出处! 文档下载:http://www.minunix.co ...
- 2 NFS高可用解决方案之NFS的搭建
preface 我们紧接着上一篇博文的基础(drbd+heartbeat的正常工作,http://www.cnblogs.com/liaojiafa/p/6129499.html)来搭建NFS的服务. ...
- 在浏览器输入 URL 后会发生什么?超级详细介绍
一个古老的面试问题:当你在浏览器中输入whosmall.com并且按下回车之后发生了什么? 不过我们不再局限于平常的回答,而是想办法回答地尽可能具体,不遗漏任何细节. 这将是一个协作的过程,所以深入挖 ...
- 日志分析 第五章 安装logstash
logstash是java应用,依赖JDK,首先需要安装JDK,在安装jdk过程中,logstash-2.3.4使用JDK-1.7版本有bug,使用JDK-1.8版本正常,因此我们安装JDK-1.8版 ...
- k-nearest-neighbor算法
1. kNN 1.1 基本的kNN模型 kNN(k-nearest neighbor)的思想简单来说就是,要评价一个未知的东西U,只需找k个与U相似的已知的东西,并通过k个已知的,对U进行评价.假如要 ...
- JSON-LD
RDF RDF用于信息需要被应用程序处理而不是仅仅显示给人观看的场合.RDF提供了一种用于表达这一信息.并使其能在应用程序间交换而不丧失语义的通用框架.既然是通用框架,应用程序设计者可以利用现成的通用 ...
- Hadoop-2.7.3 问题收集
问题1:在DFS Lcation 上不能多文件进行操作: 在Hadoop上的每个节点上修改该文件 conf/mapred-site.xml 增加: <property> < ...
- OBJ Loader Source Code
https://github.com/ChrisJansson/ObjLoader http://www.codeproject.com/Articles/798054/SimpleScene-d-s ...
- 分享jquery实现百叶窗特效的图片轮播
首先非常感谢网友嘉翼的无私分享,这是他刚在网站扣下来的特效,第一时间与大家分享,jquery实现百叶窗特效的图片轮播 使用方法: 1.引用css文件,css文件里面已经做了注释,基本只需要修改宽高就好 ...