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

C++ webrtc开发(非原生开发,linux上使用libdatachannel库)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录
  • 前言
  • 一、libdatachannel库的下载和build
  • 二、开始使用
    • 1.
    • 2.引入库
    • 3.开始使用
  • 总结

前言

使用c++开发webrtc在互联网上留下的资料甚少,经过我一段时间的探索,有大概这几种可以用于c++进行webrtc开发的方法。
1.c++ webrtc native 开发,这个开发方法很麻烦,编译这个库十分麻烦,索性网上还留有部分资料可供参考,但是因为我是想在嵌入式上部署webrtc,所以没有考虑这个方法。
2.kvs webrtc c sdk 库二次开发,利用amazon给出的用于aws的sdk,我们编译生成静态库后可以抛弃掉其中信令服务器等内容,利用里面ice部分媒体传输部分完成自己的功能的开发。优点是这个库的对外api的介绍写的挺清楚,缺点是kvs的github社区里面的问题基本都是使用它的整套服务过程中提出的问题,对于单独提取它的一些库来完成自己功能过程中遇到的问题很少,可能你在自己魔改的过程中遇到奇奇怪怪的问题里面一点线索都找不到。其次,这是一个c库,对外的api写的挺清楚,但是遇到bug后你阅读源码的过程中,大量的c代码会让你很难受。并且该库依赖大量的第三方库,编译过程比webrtc native舒适不少,但还是会遇到各种问题,尤其是你想要交叉编译到嵌入式板子上时,可能这个过程更会让你难受。关于使用这个库开发自己的webrtc的中文资料也挺少,推荐这篇博客
嵌入式中实现webrtc的方式
这条路我是跟着这篇文章做过一阵,但是最后还是失败了,如果有人这个方法做出来可以告诉我
3.libdatachannel库,这个库很轻量级,简单make就可以,虽然看名字这个库似乎只能用于datachannel,但实际他是支持媒体传输的,代码质量很高,缺点是要c++17,但是我的嵌入式板子刚好支持c++17,于是就这样使用下来了,体验很不错,基本上使用库遇到的问题你都能在github的issue中找到解决的方法。

一、libdatachannel库的下载和build

没什么好说的,因为这个库真的很轻量级,我甚至没有交叉编译,我直接在嵌入式板子上编译最终都通过了。
make就完事了,中间可能会遇到openssl库的一个问题,google一下就能解决问题。
build教学

二、开始使用

1.

如果直接使用的话,你在make之后再make install一下,大概就会把相关需要的文件放在系统的某个目录下了,你可以把include和lib自己拿出来放到项目文件夹中,或者你再cmake中指明库在系统哪个地方也行,不懂的可以问chatgpt,适当的提示词可以让gpt很快地解决你的问题。除此之外你还需要自己include一个json库,你喜欢的任意一种c++json库都行。

2.引入库

在这里插入图片描述

就像这样引入这些库吧。最重要的是rtc.hpp,别把它忘了就好

3.开始使用

大家可以照看github中examples的代码自己读,自己改出一版自己的webrtc,接下来我来用我自己的代码来做一个简单的教学,内容在代码中的注释展现

#include "../include/rtc/rtc.hpp"
#include <iostream>
#include "json.hpp"
#include <memory>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
typedef int SOCKET;
static std::string from;
static std::string to;
static std::string sessionid;using std::string;
using std::shared_ptr;
using std::weak_ptr;
using std::cout ;
using std::endl;
const int BUFFER_SIZE = 2048;
template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; }
shared_ptr<rtc::PeerConnection> pc;
rtc::WebSocket ws;
using nlohmann::json;
int main()
{// std::cout << "hehe" << std::endl;//Debug的程度,一般设置为Debug就行,Verbose会展示网络的具体细节rtc::InitLogger(rtc::LogLevel::Verbose);bool flag = false;//ws开启ws.onOpen([&flag]() {std::cout << "WebSocket open" << std::endl;flag = true;});//socket绑定,这一段代码非必须,如果你阅读了github中examples的相关内容,你应该会理解这么做是在干嘛SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);struct sockaddr_in addr = {};addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr("127.0.0.1");addr.sin_port = htons(6000);if (bind(sock, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr)) < 0)throw std::runtime_error("Failed to bind UDP socket on 127.0.0.1:6000");int rcvBufSize = 212992;setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char *>(&rcvBufSize),sizeof(rcvBufSize));//设置websocket的回调函数,里面相关的json报文解析要按照你自己的信令服务器来进行设置//我来说说里面比较重要的东西//1.setRemoteDescription(需要你传入sdp和type的string),注意当你没有持有offer时,这时里面会//自动调用setLocalDescription然后开始产生你的对offer的answer//对应于js中的写法,就相当于setremotedescription后自动调用了CreateAnswer//而你自己获得answer后却不会产生自己的sdpws.onMessage([](auto data) {// data holds either std::string or rtc::binaryif (!std::holds_alternative<std::string>(data))return;// cout <<"1111" << endl;std::string ndata = std::get<std::string>(data);std::cout << "got data" << ndata << std::endl;json message = json::parse(ndata);std::string type = message["type"].get<std::string>();// cout << "2222" <<endl;if (type == "offer") {std::cout << "get offer " << std::endl;std::string sdp = message["data"]["description"]["sdp"].get<std::string>();std::cout << "get sdp: 
" << sdp << std::endl;pc->setRemoteDescription(rtc::Description(sdp, type));} else if(type == "answer"){std::cout << "get answer " << std::endl;std::string sdp = message["data"]["description"]["sdp"].get<std::string>();std::cout << "get sdp: 
" << sdp << std::endl;pc->setRemoteDescription(rtc::Description(sdp, type));}else if (type == "candidate") {auto candidate = message["data"]["candidate"]["candidate"].get<std::string>();auto mid       = message["data"]["candidate"]["sdpMid"].get<std::string>();// auto mid = message["mid"].get<std::string>();std::cout << "get candidate:
" << candidate << std::endl;pc->addRemoteCandidate(rtc::Candidate(candidate, mid));}});////ws连接,如果你是主动发送offer方,请务必等ws连接完毕后再进行后续,否则可能会出现ws还未连接但是已经收集完description并尝试发送了ws.open("your own websocket url");// int cnt++;while(!flag){;}//stun服务器和turn服务器的设置,如果你要设置turn,其实直接写一个turn地址就够了,这个turn也会用作stun//并且你不用在ip中指明是turn还是stun,当你设置有密码和账号后,就会认为是turn了rtc::Configuration config;// config.iceServers.emplace_back("stun.l.google.com:19302");config.iceServers.emplace_back("url");// const rtc::IceServer turnServer("ip", "port", "name", "password");// config.iceServers.emplace_back(turnServer);//简单的媒体trackrtc::Description::Video media("video", rtc::Description::Direction::SendOnly);media.addH264Codec(96);media.addSSRC( rtc::SSRC(45), "video-send" );pc = std::make_shared<rtc::PeerConnection>(config);auto track = pc->addTrack(media);// pc->createdata//收集本地candidate回调,每收集到一个就会发送一个pc->onLocalCandidate([](rtc::Candidate candidate) {std::cout << "Local Candidate:"<< std::endl;std::cout << std::string(candidate) << std::endl << std::endl;// std::cout << std::string(candidate.mid()) << std::endl;json message;message["type"] = "candidate";message["data"]["from"] = "1433";message["data"]["to"] = "1453";message["data"]["candidate"]["candidate"] = std::string(candidate);message["data"]["candidate"]["sdpMid"] = candidate.mid();message["data"]["session_id"] = "1453-1433";ws.send(message.dump());});//ice状态pc->onStateChange([](rtc::PeerConnection::State state) {std::cout << "[State: " << state << "]" << std::endl;});//本地sdppc->onLocalDescription([](rtc::Description sdp){auto description = pc->localDescription();json message;message["type"] = description->typeString();message["data"]["to"] = "1453";message["data"]["from"] = "1433";message["data"]["description"]["sdp"] = string(description.value());message["data"]["description"]["type"] = description->typeString();message["data"]["session_id"] = "1453-1433";message["data"]["media"] = "video";std::cout << "send answer json :
" << message.dump() << std::endl;ws.send(message.dump());});
//没什么大用,告知candidate收集状态pc->onGatheringStateChange([](rtc::PeerConnection::GatheringState state) {cout << "Gathering State: " << state << endl;if (state == rtc::PeerConnection::GatheringState::Complete) {std::cout  << "gather ok" << std::endl;}});
// pc->setLocalDescription();// pc->onTrack)// const std::string label = "test";// std::cout << "Creating DataChannel with label "" << label << """ << std::endl;// auto dc = pc->createDataChannel(label);// 	dc->onOpen([wdc = make_weak_ptr(dc)]() {// 		// std::cout << "DataChannel from " << id << " open" << std::endl;// 		if (auto dc = wdc.lock())// 			dc->send("Hello from wl");// 	});// 	dc->onClosed([]() { std::cout << "DataChannel from " << " closed" << std::endl; });// 	dc->onMessage([wdc = make_weak_ptr(dc)](auto data) {// 		// data holds either std::string or rtc::binary// 		if (std::holds_alternative<std::string>(data))// 			std::cout << "Message from " << "peer" << " received: " << std::get<std::string>(data)// 			          << std::endl;// 		else// 			std::cout << "Binary message from " << "peer "// 			          << " received, size=" << std::get<rtc::binary>(data).size() << std::endl;// 	});char buffer[2048];int len;while ((len = recv(sock, buffer, BUFFER_SIZE, 0)) >= 0) {if (len < sizeof(rtc::RtpHeader) || !track->isOpen())continue;std::cout << "send buffer: " << len << std::endl;auto rtp = reinterpret_cast<rtc::RtpHeader *>(buffer);rtp->setSsrc(rtc::SSRC(45));track->send(reinterpret_cast<const std::byte *>(buffer), len);}//	while(1);return 0;
}

总结

libdatachannel是一个很好用的webrtc库,经过测试,它的协议栈能和firefox和flutter-webrtc兼容

相关文章:

C++ webrtc开发(非原生开发,linux上使用libdatachannel库)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、libdatachannel库的下载和build二、开始使用 1.2.引入库3.开始使用 总结 前言 使用c开发webrtc在互联网上留下的资料甚少&#xff0c;经过我一段时间的探…...

vue-router路由传参的两种方式(params 和 query )

一、vue-router路由传参问题 1、概念&#xff1a; A、vue 路由传参的使用场景一般应用在父路由跳转到子路由时&#xff0c;携带参数跳转。 B、传参方式可划分为 params 传参和 query 传参&#xff1b; C、而 params 传参又可分为在 url 中显示参数和不显示参数两种方式&#x…...

VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…...

github操作学习笔记(杂乱版)

git开源的分布式版本控制系统&#xff1a; 每次修改文件提交后&#xff0c;都会自动创建一个项目版本 查看git版本看有没有安装成功&#xff1a;git --version 把默认编辑器设置成vim&#xff1a;git config --global core.editor "vim" 1、设置昵称和邮箱&#xff…...

TaskBuilder SQL执行工具

为了方便开发者连接当前任擎服务器上配置的各个数据源对应的数据库进行相关操作&#xff0c;TaskBuilder提供了一个SQL执行工具&#xff0c;点击系统侧边栏里的执行SQL图标 &#xff0c;即可打开该工具&#xff0c;界面如下图所示&#xff1a; 该工具从上至下分为三个区域&a…...

快速掌握Quartz.Net计划任务调度框架,轻松实现定时任务

前言 Quartz.Net是一个开源的作业调度框架&#xff0c;可以用于管理计划任务和定期执行。Quartz.Net提供了丰富的作业计划选项&#xff0c;例如精确或模糊时间表达式、日期和时间限制等。Quartz.Net采用分布式架构&#xff0c;允许在多个计算机上运行任务。 Quartz.Net架构设…...

Linux ufw命令丨Linux网络防火墙ufw命令详解

ufw&#xff08;Uncomplicated Firewall&#xff09;是Ubuntu系统上默认的防火墙组件&#xff0c;它为轻量化配置iptables而开发&#xff0c;提供了一个非常友好的界面用于创建基于IPv4和IPv6的防火墙规则 ufw在Ubuntu 8.04 LTS后的所有发行版中默认可用&#xff0c;它通过命令…...

shell编程(完结)

shell编程&#xff08;完结&#xff09; 声明&#xff01; 学习视频来自B站up主 ​泷羽sec​​ 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其…...

深入了解Text2SQL开源项目(Chat2DB、SQL Chat 、Wren AI 、Vanna)

深入了解Text2SQL开源项目&#xff08;Chat2DB、SQL Chat 、Wren AI 、Vanna&#xff09; 前言1.Chat2DB2.SQL Chat3.Wren AI4.Vanna 前言 在数据驱动决策的时代&#xff0c;将自然语言查询转化为结构化查询语言&#xff08;SQL&#xff09;的能力变得日益重要。无论是小型创业…...

【Linux】报错:cannot create directory ‘test’: Read-only file system

1 报错 ❤️在使用mkdir test命令创建文件夹的时候,报错如下: mkdir:cannot create directory ‘test’:Read-only file system 2 解决方法 mount -o remount,rw / 🦋上述命令在Linux系统中用于重新挂载(root)文件系统,并将其从只读模式切换到读写模式。 ■ 下面是对…...

python mat是什么文件

.mat就是matlab的文件格式&#xff0c;一般用于matlab和python间的数据传输&#xff0c;python中numpy和scipy提供了一些函数&#xff0c;可以很好的对.mat文件的数据进行读写和处理。 在python中可以使用scipy.io中的函数loadmat()读取mat文件&#xff0c;函数savemat保存文…...

Redis: 一个高效的内存数据存储解决方案

Redis: 一个高效的内存数据存储解决方案 介绍 Redis&#xff08;Remote Dictionary Server&#xff09;是一种开源的高性能键值存储系统。它常被用作缓存、消息队列、会话存储、实时数据分析等多种场景。与传统的关系型数据库不同&#xff0c;Redis 是基于内存的数据存储&…...

AR眼镜_消费级工业AR智能眼镜主板硬件解决方案

AR眼镜的研发是一项复杂的软硬件集成工程&#xff0c;它需要在摄影、音频、交互和连接等多个方面提供卓越的基础体验&#xff0c;因此产品的每个细节都显得尤为重要。 在设计AR眼镜时&#xff0c;重量、体积和散热性能都是必须认真考量的关键因素。在芯片平台的选择上&#xff…...

C# 异常处理

C# 异常处理 异常处理是编程中不可或缺的一部分,它允许程序在遇到错误或意外情况时优雅地处理这些问题,而不是直接崩溃。C# 提供了一套强大的异常处理机制,包括 try-catch 块、finally 块和 throw 语句。本文将深入探讨 C# 中的异常处理,包括如何捕获和处理异常,以及如何…...

图解SSH原理

1. 初见SSH SSH是一种协议标准&#xff0c;其目的是实现安全远程登录以及其它安全网络服务。 SSH仅仅是一协议标准&#xff0c;其具体的实现有很多&#xff0c;既有开源实现的OpenSSH&#xff0c;也有商业实现方案。使用范围最广泛的当然是开源实现OpenSSH。 2. SSH工作原理 …...

如何快速批量把 PDF 转为 JPG 或其它常见图像格式?

在某些特定场景下&#xff0c;将 PDF 转换为 JPG 图片格式却具有不可忽视的优势。例如&#xff0c;当我们需要在不支持 PDF 查看的设备或软件中展示文档内容时&#xff0c;JPG 图片能够轻松被识别和打开&#xff1b;此外&#xff0c;对于一些网络分享或社交媒体发布的需求&…...

在CentOS中安装和卸载mysql

在CentOS7中安装和卸载mysql 卸载mysql1、查看是否安装过mysql2、查看mysql服务状态3、关闭mysql服务4、卸载mysql相关的rpm程序5、删除mysql相关的文件6、删除mysql的配置文件my.cnf 安装mysql1、下载mysql相关的rpm程序2、检查/tmp临时目录权限3、安装mysql前的依赖检查3、安…...

第十二章:异常(2)

六、自定义异常类 1. 定义一个类继承 异常类 (1) 定义异常类如果为运行时异常&#xff0c;则需要继承 RuntimeException class CheckedPasswordException extends RuntimeException{} (2) 定义异常类如果为非运行时异常&#xff0c;则需要继承 Exception class CheckedPass…...

DAY5 C++运算符重载

1.类实现> 、<、!、||、&#xff01;和后自增、前自减、后自减运算符的重载 代码&#xff1a; #include <iostream>using namespace std; class Complex {int rel;int vir; public:Complex(){};Complex(int rel,int vir):rel(rel),vir(vir){cout << "…...

Qt之点击鼠标右键创建菜单栏使用(六)

Qt开发 系列文章 - menu&#xff08;六&#xff09; 目录 前言 一、示例演示 二、菜单栏 1.MenuBar 2.Menu 总结 前言 QMainWindow是一个为用户提供主窗口程序的类&#xff0c;包含一个菜单栏&#xff08;menubar&#xff09;、多个工具栏(toolbars)、一个状态栏(status…...

Ant Design Pro实战--day01

下载nvm https://nvm.uihtm.com/nvm-1.1.12-setup.zip 下载node.js 16.16.0 //非此版本会报错 nvm install 16.16.0 安装Ant Design pro //安装脚手架 npm i ant-design/pro-cli -g //下载项目 pro create myapp //选择版本 simple 安装依赖 npm install 启动umi yarn add u…...

ejb组件(rmi) webservice平台(xml)

springboot bean 在 Spring Boot 中&#xff0c;Bean 是 Spring 框架的核心概念之一&#xff0c;表示由 Spring 容器管理的对象。通过 Bean 或其他注解&#xff08;如 Component、Service、Repository 等&#xff09;来定义和管理这些对象。以下是关于 Spring Boot 中 Bean 的…...

[高考] 学习数学的难点

最近想看一些机器学习的书&#xff0c;发现很多概念&#xff0c;很多符号&#xff0c;很多地方是&#xff0c;不知道具体的意思&#xff0c;不懂其中的内涵&#xff0c;所以需要再重新查阅很多的资料&#xff0c;去理解作者每句话是什么意思。 总结一下难点。以詹姆斯-斯图尔特…...

西门子200 smart PLC助力水处理企业自动化改造

摘要 西门子的200SMART PLC&#xff0c;以其强大的功能和灵活的应用性&#xff0c;正成为环保行业中不可或缺的一环。今天&#xff0c;我们就来看看这个小小的PLC是如何在处理环保问题中大显身手的。 不得不说&#xff0c;环保行业的痛点可不少。 比如污水处理&#xff0c;传…...

redis 怎么样查看list

在 Redis 中&#xff0c;可以通过以下方法查看列表的内容或属性&#xff1a; 1. 查看列表中的所有元素 使用 LRANGE 命令&#xff1a; LRANGE key start endkey 是列表的名称。start 是起始索引&#xff0c;0 表示第一个元素。end 是结束索引&#xff0c;-1 表示最后一个元素…...

QT数据库(二):QSqlQueryModel实现数据查询

QSqlQueryModel 可以设置任意的 SELECT 语句来从数据库中查询数据&#xff0c;可以查询一个数据表部分字段的数据&#xff0c;也可以是多个数据表组合的数据。该模型的数据是只读的&#xff0c;即使在界面上修改了QSqlQueryModel 模型的数据&#xff0c;也不能将所做的修改提交…...

【后端面试总结】HTTPS工作原理详解

引言 在现代网络通信中&#xff0c;数据的安全性至关重要。HTTP&#xff08;Hypertext Transfer Protocol&#xff09;作为互联网上传输数据的协议&#xff0c;虽然应用广泛&#xff0c;但其数据以明文形式传输&#xff0c;存在被窃取和篡改的风险。为此&#xff0c;HTTPS&…...

Kibana 部署

Kibana 是一个开源的数据可视化和探索工具&#xff0c;主要用于 Elasticsearch 数据的分析和展示。本文将详细介绍如何在 Linux 系统上部署 Kibana&#xff0c;并启用 SSL 加密以确保安全通信。 英文文档&#xff1a;Kibana Guide | Elastic 中文文档&#xff1a;Kibana 用户…...

PostgreSQL 入门

下载与安装 部分国产数据库采用PostgreSQL作为基础进行研发&#xff0c;因此先尝试了解一下原始数据库情况。 PostgreSQL 简称 PG 官网&#xff1a;https://www.postgresql.org/ PostgreSQL “世界上最先进的开源关系型数据库” 这是官网上的口号。 PostgreSQL: The World…...

简单的多网卡选择指定网卡ip注册

简单的多网卡选择指定网卡ip注册 我们公司服务器上面有多个网卡&#xff0c;多网卡则本地ip有多个ip,我们启动服务的时候需要选定他特定的ip&#xff0c;我们服务需要特定的ip进行注册&#xff0c;才能进行正常的通讯功能&#xff0c;我们需要使用如下配置进行特定ip选择&…...

【论文阅读笔记】One Diffusion to Generate Them All

One Diffusion to Generate Them All 介绍理解 引言二、相关工作三、方法预备知识训练推理实现细节训练细节 数据集构建实验分结论附录 介绍 Paper&#xff1a;https://arxiv.org/abs/2411.16318 Code&#xff1a;https://github.com/lehduong/onediffusion Authors&#xff1…...

基于Spring Boot的电影院订票信息管理系统

目录 前言 一、技术栈 二、系统功能介绍 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 当今社会已经步入了科学技术进步和经济社会快速发展的新时期&#xff0c;国际信息和学术交流也不断加强&#xff0c;计算机技术对经济社会发展和人民生活改善的影响也…...

Easy-Mock前端+后端全解以及详细使用

前文 常见的mock方式 将模拟数据直接写在代码里利用 JavaScript 拦截请求利用 Charles、 Fiddler 等代理工具拦截请求 把模拟的数据写代码里&#xff0c;那是不是每次修改返回数据就要重新部署服务&#xff0c;那有没有不用部署也能改返回参数的东西呢&#xff1f;有&#x…...

【WSL】——wsl安装多个ubuntu

原因&#xff1a;一个库用了GLIBC_2.29&#xff0c;但是我的系统是ubuntu18.04&#xff0c;看样子需要升级glibc&#xff0c;但是升级之后好像会出现崩溃的问题。参考&#xff1a;ubuntu慎重升级glibc。所以那就再安装一个ubuntu22.04吧。 下面介绍通过wsl安装ubuntu18.04&…...

微信小程序从后端获取的图片,展示的时候上下没有完全拼接,有缝隙【已解决】

文章目录 1、index.wxml2、index.js3、detail.detail为什么 .rich-text-style 样式可以生效&#xff1f;1. <rich-text> 组件的特殊性2. 类选择器的作用范围3. 样式优先级4. line-height: 0 的作用5. 为什么直接使用 rich-text 选择器无效&#xff1f; 总结 上下两张图片…...

人工智能大模型LLM开源资源汇总(持续更新)

说明 目前是大范围整理阶段&#xff0c;所以存在大量机翻说明&#xff0c;后续会逐渐补充和完善资料&#xff0c;减少机翻并增加说明。 Github上的汇总资源&#xff08;大部分英文&#xff09; awesome-production-machine-learning 此存储库包含一系列精选的优秀开源库&am…...

第二十六章 Spring之假如让你来写事务——初稿篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…...

介绍一下CSS中伪类和伪元素的概念

一、伪类&#xff08;Pseudo - Classes&#xff09; 1. 定义 伪类是添加到选择器的关键字&#xff0c;用于定义元素的特殊状态。这些状态不是由文档树中的结构或属性来表示&#xff0c;而是基于用户行为&#xff08;如鼠标悬停&#xff09;、元素状态&#xff08;如被选中&am…...

Python字符串常用操作

Python字符串常用操作 一、字符串的切片 1.1、通过下标及下标范围取值 my_str myNameIsTaichi value1 my_str[2] # 正向 N value2 my_str[-5] # 反向 从 -1 开始 a字符串分割&#xff0c;语法&#xff1a;string[end: step] start&#xff1a;头下标&#xff0c;以0开…...

解决创建laravel项目,使用国外镜像超时,国内镜像缺包的问题

解决创建laravel项目&#xff0c;使用国外镜像超时&#xff0c;国内镜像缺包的问题 一、前言二、切换镜像三、创建最新版本四、创建指定版本 一、前言 最近想下载 laravel 框架看看&#xff0c;但也遇到了些麻烦&#xff0c;这里做个记录。 二、切换镜像 先查看镜像源&#…...

帝可得-运营管理App

运营管理App Android模拟器 本项目的App客户端部分已经由前端团队进行开发完成&#xff0c;并且以apk的方式提供出来&#xff0c;供我们测试使用&#xff0c;如果要运行apk&#xff0c;需要先安装安卓的模拟器。 可以选择国内的安卓模拟器产品&#xff0c;比如&#xff1a;网…...

印闪网络:阿里云数据库MongoDB版助力金融科技出海企业降本增效

客户背景 上海印闪网络科技有限公司&#xff0c;于2017年1月成立&#xff0c;投资方包括红杉资本等多家国际知名风投公司。公司业务聚焦东南亚普惠金融&#xff0c;常年稳居行业头部。创始团队来自腾讯&#xff0c;中国团队主要由运营、风控及产研人员组成&#xff0c;核心成员…...

c++的应用

整理思维导图周五剩下的三个笔试题利用函数重载&#xff0c;实现对整形数组的冒泡排序&#xff0c;对浮点型数组的冒泡排序整理课上内容在堆区申请一个数组的空间&#xff0c;并完成对该数组中数据的输入和输出&#xff0c;程序结束释放堆区空间 冒泡排序效果图&#xff1a; 代…...

linux网络编程 | c | select实现多路IO转接服务器

select实现多路IO转接服务器 基于该视频完成 15-select实现多路IO转接设计思路_哔哩哔哩_bilibili 通过响应式–多路IO转接实现 文章目录 select实现多路IO转接服务器1.思路&功能2.代码实现warp.hwarp.cmulti_select_sever.c运行图 3.代码解释&#xff08;细节&#xf…...

在Scala中对隐式转换格式与作用

隐式对象 格式&#xff1a;implicit object 作用&#xff1a;给函数的默认参数提供隐式值 object Scala12______10 { // case class DataBase(driver: String, url: String) // // implicit object mySql extends DataBase("mysql", "localhost:300") //…...

贪心算法 - 学习笔记 【C++】

2024-12-09 - 第 38 篇 贪心算法 - 学习笔记 作者(Author): 郑龙浩 / 仟濹(CSND账号名) 贪心算法 学习课程&#xff1a; https://www.bilibili.com/video/BV1f84y1i7mv/?spm_id_from333.337.search-card.all.click&vd_source2683707f584c21c57616cc6ce8454e2b 一、基本…...

【深度学习】深刻理解ViT

ViT&#xff08;Vision Transformer&#xff09;是谷歌研究团队于2020年提出的一种新型图像识别模型&#xff0c;首次将Transformer架构成功应用于计算机视觉任务中。Transformer最初应用于自然语言处理&#xff08;如BERT和GPT&#xff09;&#xff0c;而ViT展示了其在视觉任务…...

安卓低功耗蓝牙BLE官方开发例程(JAVA)翻译注释版

官方原文链接 https://developer.android.com/develop/connectivity/bluetooth/ble/ble-overview?hlzh-cn 目录 低功耗蓝牙 基础知识 关键术语和概念 角色和职责 查找 BLE 设备 连接到 GATT 服务器 设置绑定服务 设置 BluetoothAdapter 连接到设备 声明 GATT 回…...

C++ 异常处理机制与自定义异常体系

目录 1.C语言传统的处理错误的方式 ?? 1. 终止程序 2. 返回错误码 3.实际使用中的情况 2. C异常概念?? 2.1 C异常的基本概念 2.2异常的抛出和匹配原则 2.3?异常的重新抛出 2.4 异常安全 2.5 异常规范 3. 自定义异常体系 ??? 3.1??自定义异常类 3.2??自…...

【动态库.so | 头文件.hpp】基于CMake与CMakeList编写C++自定义库

前言 最近比较忙&#xff0c;其他系列教程得等到年后一起更&#xff01;请大家多多包涵&#xff01;&#xff01;相信各位在配置C环境和各类库的时候一定经常看到如下小连招 git clone https://github.com/opencv/opencv.git cd opencv mkdir build && cd build cma…...