WebRtc实现1V1音视频通话

简介

WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音通话或视频聊天的技术,是谷歌 2010 年以 6820 万美元收购 Global IP Solutions 公司而获得的一项技术。
WebRTC 提供了实时音视频的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。

官方文档
官方中文文档
相关中文文档

应用场景

实时视频通话:WebRTC 可用于实现浏览器之间的实时视频通话,无论是一对一通话还是多方通话。这对于视频会议、在线教育和远程医疗等场景非常有用。

音频通话:除了视频通话,WebRTC 也支持浏览器之间的实时音频通话。这对于实现 VoIP(Voice over Internet Protocol)应用程序非常有用,如网络电话、语音聊天等。

屏幕共享:WebRTC 允许用户在浏览器之间共享屏幕,这在远程协作、在线培训和技术支持等场景下非常实用。

文件传输:WebRTC 不仅可以传输实时音视频数据,还可以用于浏览器之间的实时数据传输,包括文件传输。这对于实现点对点的文件共享或传输非常方便。

网络游戏:WebRTC 可以用于实现基于浏览器的实时多人游戏,因为它提供了低延迟和高质量的实时通信。

物联网(IoT):WebRTC 的轻量级特性使其适用于 IoT 设备之间的实时通信,如智能家居设备、监控摄像头等。

虚拟现实(VR)和增强现实(AR):WebRTC 可以用于在浏览器中实现 VR 和 AR 应用程序中的实时音视频通信,如多人虚拟会议、共享虚拟体验等。

共享桌面的基本原理

传统共享桌面

共享桌面的基本原理其实非常简单:
对于共享者,每秒钟抓取多次屏幕(可以是 3 次、5 次等),每次抓取的屏幕都与上一次抓取的屏幕做比较,取它们的差值,然后对差值进行压缩;如果是第一次抓屏或切幕的情况,即本次抓取的屏幕与上一次抓取屏幕的变化率超过 80%时,就做全屏的帧内压缩,其过程与 JPEG 图像压缩类似。最后再将压缩后的数据通过传输模块传送到观看端﹔数据到达观看端后,再进行解码,这样即可还原出整幅图片并显示出来。对于远程控制端,当用户通过鼠标点击共享桌面的某个位置时,会首先计算出鼠标实际点击的位置,然后将其作为参数,通过信令发送给共享端。共享端收到信令后,会模拟本地鼠标,即调用相关的 API,完成最终的操作。一般情况下,当操作完成后,共享端桌面也发生了一些变化。通过上面的描述,可以总结出共享桌面的处理过程为︰抓屏、压缩编码、传输、解码、显示、控制这几步。对于共享桌面,很多人比较熟悉的可能是 RDP ( Remote Desktop Protocal)协议,它是 Windows 系统下的共享桌面协议﹔还有一种更通用的远程桌面控制协议——VNC ( Virtual Network Console ),它可以实现在不同的操作系统上共享远程桌面,像 TeamViewer、RealVNC 都是使用的该协议。其实在 WebRTC 中也可以实现共享远程桌面的功能。但 WebRTC 的远程桌面不需要远程控制,所以其处理过程使用了视频的方式,而非传统意义上的RDP/VNC 等远程桌面协议,仍然属于音视频采集的范畴,但是这次采集的不是音视频数据而是桌面。

WebRTC 共享桌面

WebRTC 在桌面数据处理的有好几个环节:
第一个环节,共享端桌面数据的采集。WebRTC 对于桌面的采集与RDP/VNC 使用的技术是相同的,都是利用各平台所提供的相关 API 进行桌面的抓取。以 Windows 为例,可以使用下列 API 进行桌面的抓取。BitBlt : XP 系统下经常使用,在 vista 之后,开启 DWM 模式后,速度极慢。Hook :一种黑客技术,实现稍复杂。DirectX:由于 DirectX 9/10/11 之间差别比较大,容易出现兼容问题。最新的WebRTC 都是使用的这种方式GetWindowDC:可以通过它来抓取窗口。第二个环节,共享端桌面数据的编码。WebRTC 对桌面的编码使用的是视频编码技术,即 H264/VP8 等;但 RDP/VNC 则不一样,它们使用的是图像压缩技术。使用视频编码技术的好处是压缩率高,而坏处是在网络不好的情况下会有模糊等问题。第三个环节,传输。编码后的桌面数据会通过流媒体传输协议发送到观看端。对于 WebRTC 来说,当网络有问题时,数据是可以丢失的。但对于RDP/VNC 来说,桌面数据一定不能丢失。第四个环节,观看端解码。WebRTC 对收到的桌面数据通过视频解码技术解码,而RDP/VNC 使用的是图像解码技术(可对比第二个环节)。第五个环节,观看端渲染。一般会通过 OpenGL/D3D 等 GPU 进行渲染,这个 WebRTC 与 RDP/VNC 都是类似的。

其本质就是将采集源,从摄像头换成了屏幕:

//视屏通话参数,设置采集源为前置摄像头
var mediaOpts = {
audio: true,//是否采集音频
video: {
	facingMode: "user",//调用前置摄像头
	}
}
navigator.mediaDevices.getUserMedia(mediaOpts)
//视屏通话参数,设置采集源为当前屏幕
 var mediaOpts = {
        audio: true,  //是否采集音频
        video: {
            mediaSource: 'screen'  // 设置采集源为屏幕
        }
    };

navigator.mediaDevices.getUserMedia(mediaOpts)

相关API

getUserMedia() API,提示用户许可使用其网络摄像头或其他视频或音频输入(获取摄像头和麦克风的权限),通过指定一组(强制或可选)成功和失败的回调函数,可以访问本地设备媒体(音频或视频)

navigator.mediaDevices.getUserMedia(constraints, successCallback, errorCallback)

它返回一个 JS 中的 Promise 对象。如果 getUserMedia 调用成功,则可以通过 Promise 获得 MediaStream 对象,也就是说现在我们已经从音视频设备中获取到音视频数据了。
如果调用失败,比如用户拒绝该 API 访问媒体设备(音频设备、视频设备),或者要访问的媒体设备不可用,则返回的 Promise 会得到PermissionDeniedError 或 NotFoundError 等错误对象
参数 constraints,其类型为MediaStreamConstraints。它可以指定 MediaStream 中包含哪些类型的媒体轨(音频轨、视频轨),并且可为这些媒体轨设置一些限制
例:

// 该结构可以指定采集音频还是视频,或是同时对两者进行采集,比如:
const mediaStreamContrains = {
video: true,
audio: true
};

并且通过该结构,还能做进一步的设定

var constraints= {
	video :{
		width: 640,//宽度是 640
		height:480,//高度是 480
		frameRate:15,//视频的帧率 15 帧每秒
		facingMode:'enviroment'//使用后置摄像头,可选的值:user(前置摄像头)、environment(后置摄像头)、left(前置左侧摄像头)、right(前置右置摄像头)
	},
	audio : false//音频未开启
}

音视频的设定远不止这些,比如音频还可以设置为开启回音消除、降噪以及自动增益功能,视频还可以设置是否启用裁剪、所选摄像头等等。更详细的设置可以参考 WebRTC 规范

createObjectUrl() 方法指示浏览器创建和管理与本地文件或二进制对象(blob)关联的唯一URL,它在 WebRTC 中的典型用法是从 MediaStream 对象开始创建 Blob URL 。 然后,将在 HTML 页面内使用 Blob URL

createObjectURL(stream)

MediaDevices:
该接口提供了访问(连接到计算机上的)媒体设备(如摄像头、麦克风)以及截取屏幕的方法。实际上,它允许你访问任何硬件媒体设备。
MediaDeviceInfo:
用于表示每个媒体输入/输出设备的信息,包含以下 4 个属性:
deviceId: 设备的唯一标识;
groupId: 如果两个设备属于同一物理设备,则它们具有相同的组标识符 - 例如同时具有内置摄像头和麦克风的显示器;
label: 返回描述该设备的字符串,即设备名称(例如“外部 USB 网络摄像头”);
kind: 设备种类,可用于识别出是音频设备还是视频设备,是输入设备还是输出设备:audioinput/audiooutput/videoinput

MediaStream:
用于表示媒体数据流。 流可以是输入或输出,也可以是本地或远程(例如,本地网络摄像头或远程连接)
RTCPeerConnection:
建立点对点连接的关键,提供了创建,保持,监控,关闭连接的方法的实现。像媒体协商、收集候选地址都需要它来完成;调用 new RTCPeerConnection(configuration) 将创建一个 RTCPeerConnection 对象。该配置具有查找和访问 STUN 和 TURN 服务器的信息(每种类型可以有多个服务器,任何 TURN 服务器也可以用作 STUN 服务器)
STUN 服务器(Session Traversal Utilities for NAT):

  • STUN服务器用于发现客户端位于NAT后面的真实IP地址和端口。
  • 客户端在与STUN服务器进行通信时,可以获取自己的公网IP地址和端口。
  • STUN服务器不对数据流进行修改,它只是用于获取NAT后端的地址信息。
  • STUN服务器通常用于建立点对点连接,如WebRTC应用程序,其中客户端需要了解其真实的网络地址以便直接通信。

TURN 服务器(Traversal Using Relays around NAT):

  • TURN服务器用于在两个客户端无法直接通信时,作为中间转发点传输数据。其本质就是一个收发socket消息的服务器
  • 当两个客户端无法建立直接连接时(例如由于防火墙或双方均位于对称NAT后面),它们可以通过TURN服务器进行通信。
  • TURN服务器会接收客户端的数据,并将其转发给目标客户端,从而绕过了无法直接连接的障碍。
  • 虽然TURN服务器提供了中继服务,但是由于数据都要通过服务器中转,因此会增加数据传输的延迟和服务器的负载。

createOffer:
createOffer() 方法生成一个 SDP Blob,其中包含:
具有会话支持的配置 RFC3264 的 offer,
附加(attached)的 localMediaStreams 的描述,
浏览器支持的 codec/RTP/RTCP 选项,
ICE 收集的所有候选对象,
可以提供约束参数以对生成的要约提供附加控制

createAnswer:
createAnswer() 方法用于创建应答SDP

close:
close() 方法销毁 RTCPeerConnection ICE 代理,结束任何活动的 ICE 处理和任何活动的流,并释放任何相关资源

更多API介绍

基本使用

调用本地摄像头

1.创建如下目录
在这里插入图片描述
2.编写界面

<!DOCTYPE html>
<html>
  <head>
    <title>测试摄像头调用</title>
  </head>
  <body>
    <div id="mainDiv">
      <p>展示当前摄像头捕捉画面</p>
      <video autoplay></video>
      <script src="./js/getUserMedia.js"></script>
    </div>
  </body>
</html>

3.编写JS


//不同的浏览器需要使用不同的方式调用
// API method:
// Opera --> getUserMedia
// Chrome --> webkitGetUserMedia
// Firefox --> mozGetUserMedia

//获取用户摄像头权限
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// 指定采集视频,不采集音频
var constraints = {audio: false, video: true};
//获取video标签
var video = document.querySelector("video");
// 获取成功后执行的回调函数
function successCallback(stream) {

  window.stream = stream;
  if (window.URL) {
	  
   //将获取到的流展示在页面上,这种方式适用于谷歌浏览器
   video.srcObject = stream;
  } else {
    // 适用于火狐和Opera浏览器
    video.src = window.URL.createObjectURL(stream);
  }
  //播放视频
  video.play();
}
// 获取失败后执行的回调函数
function errorCallback(error) {
  console.log("navigator.getUserMedia error: ", error);
}
// 发起调用
navigator.getUserMedia(constraints, successCallback, errorCallback);

4.效果展示

火狐浏览器
在这里插入图片描述
谷歌
在这里插入图片描述

播放约束设置

1.编写界面

<!DOCTYPE html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>播放约束测试</title>
    </head>
    <body>
        <div id="mainDiv">
           
            <p>播放约束测试</p>
            <div id="buttons">
                <button id="qvga">320x240</button>
                <button id="vga">640x480</button>
                <button id="hd">1280x960</button>
            </div>
            <p id="dimensions"></p>
            <video autoplay></video>
            <script src="js/getUserMedia_constraints.js"></script>
        </div>
    </body>
</html>

2.编写JS

//获取页面的3个按钮
var vgaButton = document.querySelector("button#vga");
var qvgaButton = document.querySelector("button#qvga");
var hdButton = document.querySelector("button#hd");
// 获取视屏显示区域
video = document.querySelector("video");
//采集到的视频流
var stream;
//兼容不同浏览器调用摄像头
navigator.getUserMedia = navigator.getUserMedia ||
  navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// 调用成功后回调函数
function successCallback(gotStream) {
  //设置流
  window.stream = gotStream;

   //将获取到的流展示在页面上
   video.srcObject = stream;
  //播放视屏画面
  video.play();
}
// 获取摄像头失败回调函数
function errorCallback(error){
  console.log("navigator.getUserMedia error: ", error);
}
// 低分辨率约束
var qvgaConstraints = {
  video: {
    mandatory: {
      maxWidth: 320,
      maxHeight: 240
    }
  }
};
// 标准分辨率视频的约束对象
var vgaConstraints = {
  video: {
    mandatory: {
      maxWidth: 640,
      maxHeight: 480
    }
  }
};
// 高分辨率视频的约束对象
var hdConstraints = {
  video: {
    mandatory: {
      minWidth: 1280,
      minHeight: 960
    }
  }
};
// 点击事件
qvgaButton.onclick = function() {
  getMedia(qvgaConstraints)
};
vgaButton.onclick = function() {
  getMedia(vgaConstraints)
};
hdButton.onclick = function() {
  getMedia(hdConstraints)
};

//设置约束参数
function getMedia(constraints) {
  if (!!stream) {
    video.src = null;
    stream.stop();
  }
  navigator.getUserMedia(constraints, successCallback, errorCallback);
}

3.效果展示
在这里插入图片描述
在这里插入图片描述

媒体协商过程

一对一通信中,发起方发送的 SDP 称为Offer(提议)接收方发送的 SDP 称为Answer(应答)
每端保持两个描述:描述本身的本地描述LocalDescription,描述呼叫的远端的远程描述RemoteDescription。
当通信双方 RTCPeerConnection 对象创建完成后,就可以进行媒体协商了,大致过程如下:

1.发起方创建 Offer 类型的 SDP,保存为本地描述后再通过信令服务器发送到对端;
2.接收方接收到 Offer 类型的 SDP,将 Offer 保存为远程描述;
3.接收方创建 Answer 类型的 SDP,保存为本地描述,再通过信令服务器发送到发起方,此时接收方已知道连接双方的配置;
4.发起方接收到 Answer 类型的 SDP 后保存到远程描述,此时发起方也已知道连接双方的配置;
5.整个媒体协商过程处理完毕。
在这里插入图片描述

协议

RTP 协议和 RTCP 协议:
网络层的协议常见的有 TCP 和 UDP,对于音视频通信使用的则是 UDP。因为 TCP 协议在实现上为了保证传输的可靠,使用了滑动窗口、重发等机制,这其实对音视频通信其实是不利的。
因为音视频通信要求时延小,反而对数据的正确性要求没有那么高,人类的生理已经决定了通信过程中丢失一两帧的数据对用户的观看和收听没有太大影响,而且通过音视频算法可以做到很大程度的弥补。所以往往音视频通信都是基于 UDP 来实现的,不过不能直接把音视频数据流交给 UDP 传输,而是先给音视频数据加个 RTP 头,然后再交给 UDP 进行传输。当然,UDP 作为一种不可靠的传输,会发生丢包等情况,WebRTC 对这些问题在底层都有相应的处理策略。

什么是 RTP 头?一个视频帧的数据量是非常大的,最少也要几十K。而以太网的最大传输单元是 1500 字节,所以要传输一个帧需要拆成几十个包。并且这几十个包传到对端后,还要重新组装,这样才能进行解码还原出一幅幅的图像。要完成这样的过程,至少需要以下几个标识。
序号∶用于标识传输包的序号,这样就可以知道这个包是第几个分片了。
起始标记︰记录分帧的第一个 UDP 包。
结束标记∶记录分帧的最后一个 UDP 包。

有了上面这几个标识字段,就可以在发送端进行拆包,在接收端将视频帧重新再组装起来了。

RTP 协议就是做这个事的,其中有好几个字段,比如:
sequence number:序号,用于记录包的顺序。
timestamp:时间戳,同一个帧的不同分片的时间戳是相同的。这样就省去了前面所讲的起始标记和结束标记。
PT:Payload Type,数据的负载类型。音频流的 PT 值与视频的 PT 值是不同的,通过它就可以知道这个包存放的是什么类型的数据。

除此之外,WebRTC 还使用了 RTCP 协议让通信的两端知道它们自己的网络质量
RTCP 有两个最重要的报文:RR(Reciever Report)和 SR(Sender Report)。
通过这两个报文的交换,各端就知道自己的网络质量到底如何了。比如 SR 报文并不仅是指发送方发了多少数据,它还报告了作为接收方,它接收到的数据的情况。当发送端收到对端的接收报告时,它就可以根据接收报告来评估它与对端之间的网络质量了,随后再根据网络质量做传输策略的调整。

SDP 协议:
音视频通话时,沟通的双方必须要确保两方对音视频的数据理解是一致的,才能高效的沟通,比如 A 的音频数据采样率是 48000,使用双声道,而 B 只能支持音频采样频率是 32000,使用单声道,很明显进行通信的时候两者的音频通信使用 B 这边的格式就是最好的选择。
WebRTC 使用了 SDP(Session DescriptionProtocal)描述的各端(PC 端、Mac 端、Android 端、iOS 端等)的能力。这里的能力指的是各端所支持的音频编解码器是什么,这些编解码器设定的参数是什么,使用的传输协议是什么,以及包括的音视频媒体是什么等等。
两个客户端 / 浏览器进行 1 对 1 通话时,首先要进行信令交互,而交互的一个重要信息就是 SDP 的交换。
交换 SDP 的目的是为了让对方知道彼此具有哪些能力,然后根据双方各自的能力进行协商,协商出大家认可的音视频编解码器、编解码器相关的参数如音频通道数,采样率等、传输协议等信息。

举个例子,A 与 B 进行通讯,它们先各自在 SDP 中记录自己支持的音频参数、视频参数、传输协议等信息,然后再将自己的 SDP 信息通过信令服务器发送给对方。当一方收到对端传来的 SDP 信息后,它会将接收到的 SDP 与自己的SDP 进行比较,并取出它们之间的交集,这个交集就是它们协商的结果,也就是它们最终使用的音视频参数及传输协议了。
SDP 是文本格式的报文,WebRTC 对标准 SDP 规范做了一些调整,更具体的描述可以参考 SDP 规范

协议的交换与传输

对于通过浏览器进行 1 对 1 通话的整个流程中还需要第三方介入,方便双方进行正式交流之前的信息协商(传递协议信息),这个第三方被称为信令服务。

首先,通信双方将它们各自的媒体信息,如编解码器、媒体流参数、传输协议、IP 地址和端口等,按 SDP 格式整理好。然后,通信双方通过信令服务器交换 SDP 信息,并待彼此拿到对方的 SDP 信息后,找出它们共同支持的媒体能力。
最后,双方按照协商好的媒体能力建立连接开始音视频通信。

以上过程如图所示:
在这里插入图片描述

WebRTC 通信过程

WebRTC 实现一对一通信需要满足的基本条件:

WebRTC 终端(两个):本地和远端,负责音视频采集、编解码、NAT 穿越以及音视频数据传输等;
信令服务器:自行实现的信令服务,负责信令处理,如加入房间、离开房间、媒体协商消息的传递等;
STUN/TURN 服务器:负责获取 WebRTC 终端在公网的 IP 地址,以及 NAT 穿越失败后的数据中转服务。

通信过程如下:

  1. 本地(WebRTC 终端)启动后,检测设备可用性,如果可用后开始进行音视频采集工作;
  2. 本地就绪后,发送“加入房间”信令到 信令服务器;
  3. 信令服务器创建房间,等待加入;
  4. 对端(WebRTC 终端)同样操作,加入房间,并通知另一端;
  5. 双端创建媒体连接对象RTCPeerConnection,进行媒体协商;
  6. 双端进行连通性测试,最终建立连接;
  7. 将采集到的音视频数据通过RTCPeerConnection对象进行编码,最终通过 P2P 传送给对端/本地,再进行解码、展示。

ICE Candidate(ICE 候选者)

ICE 候选者表示 WebRTC 与远端通信时使用的协议、IP 地址和端口,结构如下:

{
  address: xxx.xxx.xxx.xxx, // 本地IP地址
  port: number, // 本地端口号
  type: 'host/srflx/relay', // 候选者类型
  priority: number, // 优先级
  protocol: 'udp/tcp', // 传输协议
  usernameFragment: string // 访问服务的用户名
  ...
}

WebRTC 在进行连接测试后时,通信双端会提供众多候选者,然后按照优先级进行连通性测试,测试成功就会建立连接。
候选者 Candidate 类型,即 type 分为三种类型:
host:本机候选者,就是本机的 ip 地址 和端口
优先级最高,host 类型之间的连通性测试就是内网之间的连通性测试,P2P。

srflx:内网主机映射的外网地址和端口,使用STUN 协议获取
如果 host 无法建立连接,则选择 srflx 连接,即 P2P 连接。

relay:中继候选者,使用TURN 协议获取
优先级最低,只有上述两种不存在时,才会走中继服务器的模式,因为会增加传输时间,优先级最低

1V1视频通话

  • 通话过程
    在这里插入图片描述
  • 实现效果
    在这里插入图片描述
  • 代码地址
    gitee

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/760492.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32之四:TIM定时器(1-基本定时器)

目录 1. STM32有哪些定时器 2. 基本定时器 2.1 基本定时器主要功能 2.2 基本定时器的框图 2.2.1 时钟输入 2.2.2 至DAC 2.2.3 至时基单元&#xff08;重点&#xff09; 2.2.4 影子寄存器 2.2.5 基本定时器寄存器说明 2.2.5.1 控制寄存器1&#xff08;TIMx_CR1&#x…

压缩包怎么解压,解压压缩包不损坏文件

常见格式&#xff1a; ZIP&#xff1a;最常见的压缩文件格式之一&#xff0c;支持跨平台。RAR&#xff1a;另一种常见的压缩文件格式&#xff0c;通常压缩率比ZIP高&#xff0c;但不如ZIP普及。7Z&#xff1a;来自7-Zip的压缩格式&#xff0c;支持更高的压缩率和一些高级特性。…

设计NOR Flash(FMSC接口)的Flashloader(MCU: stm32f4)

目录 概述 1 硬件 1.1 MCU和S29GL128P10TFI01控制电路 1.1.1 S29GL128P10TFI01 1.1.2 MCU与NOR Flash接口 1.2 STM32F4的FSMC接口 1.2.1 时序信号 1.2.2 外部存储器接口信号 2 Flash leader功能实现 2.1 框架结构介绍 2.2 S29GL128P10TFI01的Flash leader框架 2.3 N…

人工智能期末复习笔记(更新中)

分类问题 分类&#xff1a;根据已知样本的某些特征&#xff0c;判断一个新的样本属于哪种已知的样本类 垃圾分类、图像分类 怎么解决分类问题 分类和回归的区别 1. 逻辑回归分类 用于解决分类问题的一种模型。根据数据特征或属性&#xff0c;计算其归属于某一类别 的概率P,…

66、基于长短期记忆 (LSTM) 网络对序列数据进行分类

1、基于长短期记忆 (LSTM) 网络对序列数据进行分类的原理及流程 基于长短期记忆&#xff08;LSTM&#xff09;网络对序列数据进行分类是一种常见的深度学习任务&#xff0c;适用于处理具有时间或序列关系的数据。下面是在Matlab中使用LSTM网络对序列数据进行分类的基本原理和流…

XJTUSE-数据结构-homework1

任务 1 题目&#xff1a; 排序算法设计&#xff1a; 需要写Selection、Shell、Quicksort 和 Mergesort四种排序算法&#xff0c;书上讲述比较全面而且不需要进行额外的优化&#xff0c;下面我简要地按照自己的理解讲述。 Selection&#xff08;选择排序&#xff09;&#xff…

HarmonyOS Next开发学习手册——单选框 (Radio)

Radio是单选框组件&#xff0c;通常用于提供相应的用户交互选择项&#xff0c;同一组的Radio中只有一个可以被选中。具体用法请参考 Radio 。 创建单选框 Radio通过调用接口来创建&#xff0c;接口调用形式如下&#xff1a; Radio(options: {value: string, group: string})…

Linux常用工具使用方式

目录 常用工具&#xff1a; 安装包管理工具&#xff1a; 查找含有关键字的软件包 安装软件 安装文件传输工具 安装编辑器 C语言编译器 C编译器 安装调试器 安装项目版本管理工具 cmake 卸载软件 安装jsoncpp 安装boost库 安装mariadb 安装tree&#xff08;让目录…

Python28-3 朴素贝叶斯分类算法

朴素贝叶斯算法简介 朴素贝叶斯&#xff08;Naive Bayes&#xff09;算法是一种基于贝叶斯定理的分类算法。它广泛应用于文本分类、垃圾邮件检测和情感分析等领域。该算法假设特征之间是独立的&#xff0c;这个假设在实际情况中可能并不完全成立&#xff0c;但Naive Bayes在许…

java笔记(30)——反射的 API 及其 使用

文章目录 反射1. 什么是反射2. 获取class字段&#xff08;字节码文件对象&#xff09;方式1方式2方式3应用 3. 获取构造方法和权限修饰符前期准备获取所有的公共构造方法获取所有的构造方法获取无参构造方法获取一个参数的构造方法获取一个参数的构造方法获取两个参数的构造方法…

Java面试题--JVM大厂篇之G1 GC的分区管理方式如何减少应用线程的影响

目录 引言: 正文: 1. 区域划分&#xff08;Region&#xff09; 2. 并行和并发回收 3. 区域优先回收&#xff08;Garbage First&#xff09; 4. 可预测的停顿时间 5. 分阶段回收 6. 复制和压缩 实际效果: 场景举例 1. 减少单次GC的影响 2. 支持高并发环境 3. 优…

数学建模(1):期末大乱炖

1 概述&#xff01;&#xff01; 1.1 原型和模型 原型&#xff1a;客观存在的研究对象称为原型&#xff0c;也称为“系统”、“过程”。 机械系统、电力系统、化学反应过程、生产销售过程等都是原型&#xff1b; 研究原型的结构和原理&#xff0c; 从而进行优化、预测、评价…

一区算法MPA|海洋捕食者算法原理及其代码实现(Matlab/Python))

Matlab/Python&#xff1a; 本文KAU将介绍一个2020年发表在1区期刊ESWA上的优化算法——海洋捕食者算法 (Marine Predators Algorithm&#xff0c;MPA)[1] 该算法由Faramarzi等于2020年提出&#xff0c;其灵感来源于海洋捕食者之间不同的觅食策略、最佳相遇概率策略、海洋记…

【MySQL】Linux下MySQL的目录结构、用户、权限与角色

一、Linux下MySQL的目录结构 1、MySQL相关目录 数据库文件存放路径&#xff1a;/var/lib/mysql数据库命令存放路径&#xff1a;/user/bin和/user/sbin配置文件目录&#xff1a;/usr/share/mysql-8.0/、/usr/share/mysql/和/etc/my.cnf 2、假设我们创建了一个数据库dbtest1&a…

使用evo工具比较ORB-SLAM3的运行轨迹(从安装到解决报错)

ORB-SLAM2和ORB-SLAM3怎么跑出来&#xff0c;之前都有相关的保姆级的教程&#xff0c;下来给大家介绍一款evo工具&#xff0c;给科研加速&#xff01;&#xff01;&#xff01; 文章目录 1.下载evo2.生成轨迹3.evo别的功能使用 1.下载evo 输入命令下载 pip install -i https…

你真的会udf提权???数据库权限到系统权限 内网学习 mysql的udf提权操作 ??msf你会用了吗???

我们在已经取得了数据库的账号密码过后&#xff0c;我们要进一步进行提取的操作&#xff0c;我们mysql有4钟提权的操作。 udf提权(最常用的)mof提权启动项提权反弹shell提权操作 怎么获取密码操作&#xff1a; 怎么获取密码&#xff0c;通过sql注入获取这个大家都应该知道了&a…

百强韧劲,进击新局 2023年度中国医药工业百强系列榜单发布

2024年&#xff0c;经济工作坚持稳中求进、以进促稳、先立后破等工作要求。医药健康行业以不懈进取的“韧劲”&#xff0c;立身破局&#xff0c;迎变启新。通过创新和迭代应对不确定性&#xff0c;进化韧性力量&#xff0c;坚持高质量发展&#xff0c;把握新时代经济和社会给予…

零基础开始学习鸿蒙开发-读书app简单的设计与开发

目录 1.首页设计 2.发现页面的设计 3.设置页面的设计 4.导航页设计 5.总结&#xff1a; 6.最终的效果 1.首页设计 Entry Component export struct home {State message: string 首页build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.B…

基于线调频小波变换的非平稳信号分析方法(MATLAB)

信号处理领域学者为了改进小波变换在各时频区间能量聚集性不高的缺点&#xff0c;有学者在小波分析基础上引入调频算子构成了线性调频小波变换&#xff0c;线调频小波一方面继承了小波变换的理论完善性&#xff0c;另一方面用一个新的参数&#xff08;线调频参数&#xff09;刻…

构建高效业财一体化管理体系

构建高效业财一体化管理体系 业财一体化战略意义 提升决策质量 强化数据支撑&#xff1a;通过整合业务与财务数据&#xff0c;为决策提供准确、实时的信息基础&#xff0c;确保分析的深度与广度。促进业务与财务协同&#xff1a;打破信息孤岛&#xff0c;实现业务流程与财务管…