当前位置: 首页 > news >正文

rtmp协议转websocketflv的去队列积压

websocket server的优点

websocket server的好处:WebSocket 服务器能够实现实时的数据推送,服务器可以主动向客户端发送数据

1 不需要客户端不断轮询。
2 不需要实现httpserver跨域。
在需要修改协议的时候比较灵活,我们发送数据的时候比较方便,因为两边可以随时发送协议, 且做客户端的程序更为方便,websocket协议头部已经定义了包长,使用大部分库可以直接收数据,解决了粘包的问题,所以websocket协议是一个使用比较顺畅的协议

实现websocket server

先用boost 的协程顶一下,主要是需要将http协议升级到websocket, 因此在一个函数里面实现两种server的接收,http协议顺便就接收了,同时在客户端里面存储所有的链接对象,以下是主要实现的握手协议代码,以供参考

bool func_hand_shake(boost::asio::yield_context &yield){DEFINE_ECasio::streambuf content_;size_t length = asio::async_read_until(v_socket, content_, "\r\n\r\n", yield[ec]);ERROR_RETURN_FALSEasio::streambuf::const_buffers_type bufs = content_.data();std::string lines(asio::buffers_begin(bufs), asio::buffers_begin(bufs) + length);//std::cout<<lines<<std::endl;c_header_map hmap;//std::string get;int protocol = fetch_head_info(lines, hmap, v_app_stream);if (protocol != GET)return false;cout << "GET:" << v_app_stream << endl; //like this--> live/1001 rtmp server must like thisauto iter = hmap.find("Upgrade");if (iter == hmap.end()){//it is the http protocol ,not websocket//func_hand_http(m, yield);size_t ret = boost::asio::async_write(v_socket, boost::asio::buffer(FLV_HTTP_HEADERS,FLV_HTTP_HEADERS_LEN), yield[ec]);//ERROR_RETURN_FALSEv_key = hash_add(v_app_stream.c_str(), HASH_PRIME_MIDDLE);if (c_hubs::instance()->push(v_key, shared_from_this(), true) !=0){//we can not find the stream //return 404 errorif (ret == -1){size_t len_ = sizeof(buffer404) - 1; //remove the '\0' one bytesasio::async_write(v_socket, asio::buffer(buffer404, len_), yield[ec]);//ERROR_RETURN_FALSE//return false;}return false;}return true;}else{v_iswebsocket = true;std::string response, key, encrypted_key;//find the get//std::string request;size_t n = lines.find_first_of('\r');//find the Sec-WebSocket-Keysize_t pos = lines.find("Sec-WebSocket-Key");if (pos == lines.npos)return false;size_t end = lines.find("\r\n", pos);key = lines.substr(pos + 19, end - pos - 19) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";//get the base64 encode string with sha1
#if 0boost::uuids::detail::sha1 sha1;sha1.process_bytes(key.c_str(), key.size());unsigned int digest[5];sha1.get_digest(digest);
#endif
#if 1SHA1 sha;unsigned int digest[5];sha.Reset();sha << key.c_str();sha.Result(digest);
#endiffor (int i = 0; i < 5; i++) {digest[i] = htonl(digest[i]);}encrypted_key = base64_encode(reinterpret_cast<const uint8_t*>(&digest[0]), 20);//base64_encode(first, encrypted_key);/*The handshake from the server looks as follows :HTTP / 1.1 101 Switching ProtocolsUpgrade : websocketConnection : UpgradeSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =Sec-WebSocket-Protocol: chat*///set the response textresponse.append("HTTP/1.1 101 WebSocket Protocol Handshake\r\n");response.append("Upgrade: websocket\r\n");response.append("Connection: Upgrade\r\n");response.append("Sec-WebSocket-Accept: " + encrypted_key + "\r\n\r\n");//response.append("Sec-WebSocket-Protocol: chat\r\n");//response.append("Sec-WebSocket-Version: 13\r\n\r\n");size_t ret = boost::asio::async_write(v_socket, boost::asio::buffer(response), yield[ec]);//ERROR_RETURN_FALSE//calculate the hash key v_key = hash_add(v_app_stream.c_str(), HASH_PRIME_MIDDLE);c_hubs::instance()->push(v_key, shared_from_this(),false);}return true;}

在这里插入图片描述

rtmp协议

这个协议太过出名,实在没什么好说的

实现http协议

实现websocket协议的时候顺带实现,使用map数据结构存储

转发单线程,去除队列

1 数据共享
在发送数据的时候,rtmp 和 httpflv发送 以及 websocket发送使用同一缓存,这样有一个问题,即使我们使用共享的数据结构同时使用同一个内存,也不一定会共享申请内存时多余的头部,以下是数据结构

typedef struct s_memory
{//head uint8_t *v_data = NULL;//v_data_h =>rtmp use ituint8_t *v_data_h = NULL;//real datauint8_t *v_data_r = NULL;//uint8_t *v_data   = NULL;size_t   v_len;uint32_t v_ts; // timestampen_flv_header v_av_type = en_flv_null;void memory_create(uint32_t size, int header = 18){//zero copy//the last reserve 4 bytes for flv write 4 bytes tail for av data size//the header 18 bytes for max rtmp usev_data = new uint8_t[size + header +4];v_len    = size; //not include the header and tail //we do not know the head where//v_data_h = v_data;v_data_r = v_data + header;}void memory_create(uint32_t size, int header, int tail){v_data = new uint8_t[size + header + tail];v_len = size; //not include the header and tail v_data_h = v_data;v_data_r = v_data + header;}~s_memory(){if (v_data != NULL)delete[] v_data;}
}s_memory;

这边要做的就是在申请内存时多申请上头部和尾部,这样,使用的时候就可以在数据前面增加不同协议的数据头部。
所以是下面这句话

v_data = new uint8_t[size + header + tail];

读者自行理解就好
在这里插入图片描述
收到数据以后不进行任何的数据拷贝, 在缓冲数据前面加上数据头部,立刻发送出去,上图可以看到,rtmp协议和websocket flv 同时打开,vlc的rtmp协议稍稍会延后一点时间。两路内存占用如下图所示:

在这里插入图片描述
可以看到去除队列积压,内存占用比较小

多个线程需要修改头部的情况

如果使用多个线程,如何在各类协议之间共享数据呢,这是个问题,我们退而求其次,利用tcp 协议的特点,它是可以分开来发送批量数据,下图是使用websocket协议发送flv数据的示例,包括发送tag,taglen,data,datalen, 以及自身websocket发送的头部字节,分了三次发送,head和headlen 是实现websocket的头部而写。

/*sock      : need send socketdata      : flv av datadatalen   : flv av data len
*/
bool c_flvserver::func_set_head_send(tcp::socket &sock,uint8_t* tag, int taglen, uint8_t *data, size_t datalen,asio::yield_context &yield)
{uint8_t buffer[10];uint8_t *head = NULL;// buf;// 0x82;int headlen = 0;int totallen = taglen + datalen;if (totallen <= 65535){if (totallen < 126){head = &buffer[0] +8;//relen += 1;*head = 0x82; //0x81:1000 0001 text code ; // 1000 0010 binary code*(head + 1) = (uint8_t)totallen;headlen = 2;}else //>=126 <65536{head = &buffer[0] +6;*head = 0x82;*(head + 1) = 126;*(head + 2) = (uint8_t)((totallen >> 8) & 0xFF);*(head + 3) = (uint8_t)(totallen & 0xFF);headlen = 4;}}else //>65535{head = &buffer[0];*head = 0x82;*(head + 1) = 127;*(head + 2) = 0;   //>>56*(head + 3) = 0;   //>>48*(head + 4) = 0;// >>40*(head + 5) = 0; // >> 32;*(head + 6) = (uint8_t)(totallen >> 24);*(head + 7) = (uint8_t)(totallen >> 16);*(head + 8) = (uint8_t)(totallen >> 8);*(head + 9) = (uint8_t)(totallen & 0xFF);headlen = 10;}DEFINE_ECasio::async_write(sock, asio::buffer(head, headlen), yield[ec]);asio::async_write(sock, asio::buffer(tag, taglen), yield[ec]);asio::async_write(sock, asio::buffer(data, datalen), yield[ec]);//send the data//flv_const_buffer bb(frame, framelen,tag,taglen, data, dlen);//asio::async_write(sock, bb, yield[ec]);return ec? false : true;
}

这样在发送rtmp协议的时候,使用申请内存的多余头部空间,发送flv的时候 previous tag 长度四字节放在尾部,发送http协议的时候和flv类似,不需要发送websocket的头部字节,后面加上各类协议,比如rtsp 的tcp等等,也可以这样做,我们可以拷贝,但也可以不拷贝数据而进行零拷贝,零队列发送。

下面多打开几路观察内存

在这里插入图片描述

如下图所示:和刚才区别不大,小于10路内存都在1兆多以内
在这里插入图片描述

后面需要做的实现

实现更多的具体行业应用层服务和比较标准的协议输出, 将会做客户端发流,客户端收留,服务器对接,服务调用gpu等等,会比较谨慎。

相关文章:

rtmp协议转websocketflv的去队列积压

websocket server的优点 websocket server的好处&#xff1a;WebSocket 服务器能够实现实时的数据推送&#xff0c;服务器可以主动向客户端发送数据 1 不需要客户端不断轮询。 2 不需要实现httpserver跨域。 在需要修改协议的时候比较灵活&#xff0c;我们发送数据的时候比较…...

Elasticsearch实战应用:构建高效搜索引擎

在大数据时代&#xff0c;如何高效存储和检索海量信息成为了一个重要课题。Elasticsearch作为一个开源的分布式搜索引擎&#xff0c;以其强大的搜索能力和灵活的扩展性&#xff0c;成为了许多企业和开发者的首选。本文将深入探讨Elasticsearch的实战应用&#xff0c;包括基本概…...

Hive数仓操作(四)

一、Hive 创建表案例一&#xff08;ARRAY数组类型&#xff09; 1. 准备数据文件 首先&#xff0c;准备一个名为 stu2.txt 的文件&#xff0c;文件内容示例如下&#xff1a; 1001 Alice fish,cat 1002 Bob dog,rabbit 1003 Charlie bird注意&#xff1a; …...

《C++跨平台开发:突破界限,释放无限可能》

在当今的软件开发领域&#xff0c;跨平台开发已成为一种重要趋势。它允许开发者编写一次代码&#xff0c;然后在多个不同的操作系统和硬件平台上运行&#xff0c;极大地提高了开发效率和软件的可扩展性。而 C作为一种强大的编程语言&#xff0c;也具备实现跨平台开发的能力。本…...

速盾:免备案服务器?

速盾是一家提供网络安全服务的公司&#xff0c;其主要产品包括CDN加速、WEB防护、WAF、DDoS防护等。在网站建设过程中&#xff0c;选择一个合适的服务器是非常重要的一步。传统的服务器需要备案&#xff0c;涉及到较多的流程和审批时间&#xff0c;给网站运营带来了一定的麻烦。…...

Electron获取nodejs和chrome版本信息

Electron获取nodejs和chrome版本信息 环境&#xff1a; electron: 30.1.1 nodejs: 20.14.0代码 $ tree . --- index.html --- index.js --- package.jsonindex.html <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>H…...

【React】setState 批量更新

setState 批量更新的过程 React 的 setState 调用是异步的。为了性能原因&#xff0c;React 会将多个 setState 调用合并成一次批量更新。具体过程如下&#xff1a; 1&#xff09;React 先将调用的每个 setState 所产生的更新对象存储在一个队列中。 2&#xff09;在所有的同步…...

微信小程序开发日记第二天

坚持在各个平台更新自己写小程序的心得体会&#xff0c;在百度贴吧和csdn更新自己的小程序日记&#xff0c;同时也是个体不断地对于云技术的开发和成长&#xff0c;进行提升&#xff01;不断地将开源开放创新思维运用到自己的小程序当中&#xff0c;小程序制作的关键就是&#…...

如果您忘记了 Apple ID 和密码,按照指南可重新进入您的设备

即使您的 iPhone 或 iPad 由于各种原因被锁定或禁用&#xff0c;也可以使用 iTunes、“查找我的”、Apple 支持和 iCloud 解锁您的设备。但是&#xff0c;此过程需要您的 Apple ID 和密码来验证所有权并移除激活锁。如果您忘记了 Apple ID 和密码&#xff0c;请按照我们的指南重…...

Top4免费音频剪辑软件大比拼,2024年你选哪一款?

现在我们生活在一个数字化的时代&#xff0c;音频内容对我们来说很重要。不管是给自己拍的视频配背景音乐、整理开会时的录音&#xff0c;还是自己写歌&#xff0c;有个好用的音频剪辑软件都特别重要。今天&#xff0c;我要给大家介绍几款特别好用的音频剪辑软件免费的&#xf…...

基于SSM的电影院售票系统设计与实现

文未可获取一份本项目的java源码和数据库参考。 前言 近些年的电影在人们文娱活动中占据重要地位&#xff0c;另外&#xff0c;由于人们的生活越来越富有&#xff0c;越来越多的人们不再选择在家里看电影&#xff0c;而是选择去电影院看电影。但是&#xff0c;以往的售票方式是…...

uniapp 必须掌握的细节

1.使用watch实现实时监控的效果 例如&#xff1a;实时监测手机号码的示例 // 实时监测手机号码 watch(() > UserRegisterForm.value.phone, (newPhone) > {// 简单的手机号码正则表达式验证const phoneRegex /^1[3-9]\d{9}$/;tips.value.tipPhone !phoneRegex.test(n…...

JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)

目录 Dialog对话框 介绍 使用 实际效果 Form表单 介绍 使用 实际效果 Dialog对话框 介绍 Dialog对话框&#xff1a;在保留当前页面状态的情况下&#xff0c;告知用户并承载相关操作。 Dialog 对话框组件可以在保留当前页面信息的状态下弹出一个对话框&#xff0c;并…...

一个月学会Java 第2天 认识类与对象

Day2 认识类与对象 第一章 初识类 经过一个程序的编写&#xff0c;应该对程序的结构有点好奇了吧&#xff0c;如果你有基础&#xff0c;接下来的肯定非常的易懂&#xff0c;如果你没有基础也没有关系&#xff0c;反复琢磨一下也就懂了&#x1f606; 我们来重复一下第一个程序 …...

【WRF数据准备】MODIS静态地理数据下载及制备

【WRF数据准备】MODIS静态地理数据下载及制备 MODIS数据介绍数据下载数据拼接MRT工具介绍基于MRT软件完成数据拼接 格式转换&#xff1a;tif文件转二进制格式编写INDEX修改GEOGRID.TBL以及namelist.wps修改GEOGRID.TBL修改namelist.wps 参考 MODIS数据介绍 MODIS-MCD12Q1 v061…...

MySQL数据库——索引

目录 什么是索引&#xff08;Index&#xff09;&#xff1f; 怎样加索引&#xff1f; 索引的特点 索引类型 主键索引(Primary Key) 辅助索引&#xff08;二级索引&#xff09; 聚集索引和非聚集索引 聚集索引 非聚集索引 单列索引和联合索引 单列索引 联合索引 创…...

【SpringCloud】服务注册/服务发现-Eureka

服务注册/服务发现-Eureka 1. 背景1.1 问题描述1.2 解决思路1.3 什么是注册中⼼1.4 CAP理论1.5 常⻅的注册中⼼ 2. Eureka 介绍3. 搭建Eureka Server 1. 背景 1.1 问题描述 上个章节的例⼦中可以看到, 远程调⽤时, 我们的URL是写死的 String url "http://127.0.0.1:90…...

让你的Github Profile高大时尚!

目录 前言 正文 GitHub Profile 特点&#xff1a; GitHub Actions 核心概念&#xff1a; 应用场景&#xff1a; RSS RSS的主要特点&#xff1a; 使用场景&#xff1a; RSS的工作原理&#xff1a; 关于Github Readme Card 关于Github贡献的3D图 关于个人最新博文的获取 关于代码…...

ElasticSearch备考 -- Multi match

一、题目 索引task有3个字段a、b、c&#xff0c;写一个查询去匹配这三个字段为mom&#xff0c;其中b的字段评分比a、c字段大一倍&#xff0c;将他们的分数相加作为最后的总分数 二、思考 通过题目要求对多个字段进行匹配查询&#xff0c;可以考虑multi match、bool query操作。…...

滚雪球学Oracle[2.5讲]:数据库初始化配置

全文目录&#xff1a; 前言一、配置文件的高级参数设置1.1 open_cursors&#xff1a;游标打开数量限制案例演示 1.2 session_cached_cursors&#xff1a;会话缓存游标数量案例演示 1.3 pga_aggregate_target与sga_target&#xff1a;内存分配优化案例演示 二、内存管理模式的选…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...

前端高频面试题2:浏览器/计算机网络

本专栏相关链接 前端高频面试题1&#xff1a;HTML/CSS 前端高频面试题2&#xff1a;浏览器/计算机网络 前端高频面试题3&#xff1a;JavaScript 1.什么是强缓存、协商缓存&#xff1f; 强缓存&#xff1a; 当浏览器请求资源时&#xff0c;首先检查本地缓存是否命中。如果命…...