webrtc的RTCPeerConnection使用

背景:

平時我們很少會需要使用到點對點單獨的通訊,即p2p,一般都是點對服務端通訊,但p2p也有自己的好處,即通訊不經過服務端,從服務端角度這個省了帶寬和壓力,從客戶端角度,通訊是安全,且快速的,當然有些情況下可能速度并不一定快。那么如何實現p2p呢?

解決辦法:

webrtc的RTCPeerConnection就實現了p2p的功能,使用RTCPeerConnection需要理解一些概念,什么是信令,信令交換的過程,信令服務器。

信令

2個設備需要通訊,就需要知道對方的在互聯網上的公開地址,一般情況下2個設備都是不會直接擁有一個公網的ip地址,所以他們之間的通訊,就需要如何在公網找到自己的方式,路由信息告訴對方,通常這個信息都是臨時的,并非永久,當對方獲取到這個信息后,就可以通過網絡找到彼此的實際路由路徑,從而進行通訊,這個信息就是信令(位置信息)。

信令的交換過程:

假設2個設備,p1要和p2進行通訊

1.p1發起邀請階段

const offer = await p1.createOffer();//創建邀請信令
await p1.setLocalDescription(offer);//設置為本地信令send(JSON.stringify(offer));//把邀請信令發送給對方,至于怎么發送,一般是需要一個第3方的信令服務器來轉發這個信息

2.p2收到邀請階段

?當收到p1發起的有邀請信令offer后

await p2.setRemoteDescription(new RTCSessionDescription(JSON.parse(offer)));//設置為遠端的信令const answer = await p2.createAnswer();//創新一個應答信令,告訴p1我的位置
await pc.setLocalDescription(answer);//設置我的位置send(JSON.stringify(answer ));將位置信息發送給p1

3.p1收到應答信息階段

await p2.setRemoteDescription(new RTCSessionDescription(JSON.parse(answer )));//設置為遠端的信令
4.處理onicecandidate事件,確認要不要通訊
?await p2.addIceCandidate(new RTCIceCandidate(JSON.parse(candidate)));

完成上述幾個階段,正常來說就能開始通訊了

數據通訊DataChannel的使用

發送端

// 創建PeerConnection對象
const pc = new RTCPeerConnection();// 創建DataChannel
const dataChannel = pc.createDataChannel('myDataChannel');// 監聽DataChannel的open事件
dataChannel.onopen = () => {console.log('DataChannel已打開');
};// 監聽DataChannel的error事件
dataChannel.onerror = (error) => {console.error('DataChannel錯誤:', error);
};// 監聽DataChannel的close事件
dataChannel.onclose = () => {console.log('DataChannel已關閉');
};// 發送文本消息
function sendMessage(message) {dataChannel.send(message);
}// 發起PeerConnection連接
// ...// 在某個事件觸發時調用sendMessage()發送消息
// sendMessage('Hello, world!');

接收端:

// 創建PeerConnection對象
const pc = new RTCPeerConnection();// 監聽DataChannel的open事件
pc.ondatachannel = (event) => {const dataChannel = event.channel;// 監聽DataChannel的message事件dataChannel.onmessage = (event) => {const message = event.data;console.log('接收到消息:', message);};// 監聽DataChannel的error事件dataChannel.onerror = (error) => {console.error('DataChannel錯誤:', error);};// 監聽DataChannel的close事件dataChannel.onclose = () => {console.log('DataChannel已關閉');};
};

datachannel的用法發送端和接收端用法是一樣的,只是接收端,需要通過?onicecandidate的事件才能獲取到。

單頁面完整demo

<!DOCTYPE html>
<html>
<head><title>WebRTC Demo</title>
</head>
<body><h1>WebRTC Demo</h1><button onclick="start()">Start</button><button onclick="call()">Call</button><button onclick="hangup()">Hang Up</button><button onclick="sendMessage()">send</button><br><br><textarea id="localDesc"></textarea><br><br><textarea id="remoteDesc"></textarea><br><br><textarea id="message"></textarea><br><br><textarea id="received"></textarea><script>let localConnection, remoteConnection,dataChannel,receiveChannel;function start() {localConnection = new RTCPeerConnection();remoteConnection = new RTCPeerConnection();localConnection.onicecandidate = e => {if (e.candidate) {console.log("localConnection.onicecandidate")remoteConnection.addIceCandidate(e.candidate);}};remoteConnection.onicecandidate = e => {if (e.candidate) {console.log("remoteConnection.onicecandidate")localConnection.addIceCandidate(e.candidate);}};localConnection.oniceconnectionstatechange = e => {console.log('Local ICE connection state change:', localConnection.iceConnectionState);};remoteConnection.oniceconnectionstatechange = e => {console.log('Remote ICE connection state change:', remoteConnection.iceConnectionState);};remoteConnection.ondatachannel = e => {console.log("ondatachannel",e)receiveChannel = e.channel;receiveChannel.onmessage = e => {console.log("onmessage",e.data)document.getElementById('received').value += e.data + '\n';};};dataChannel = localConnection.createDataChannel('dataChannel');dataChannel.onopen = e => {console.log("onopen")console.log('Data channel opened');};dataChannel.onclose = e => {console.log("onclose")console.log('Data channel closed');};dataChannel.onmessage = event => {console.log("onmessage",event.data)};
}async function call() {console.log("createOffer")const offer = await localConnection.createOffer();await localConnection.setLocalDescription(offer);await remoteConnection.setRemoteDescription(offer);console.log("createAnswer")const answer = await remoteConnection.createAnswer();await remoteConnection.setLocalDescription(answer);await localConnection.setRemoteDescription(answer);document.getElementById('localDesc').value = localConnection.localDescription.sdp;document.getElementById('remoteDesc').value = remoteConnection.localDescription.sdp;}async function hangup() {await localConnection.close();await remoteConnection.close();localConnection = null;remoteConnection = null;}function sendMessage() {const message = document.getElementById('message').value;//const dataChannel = localConnection.createDataChannel('dataChannel');dataChannel.send(message);console.log("send",message)}</script>
</body>
</html>

不同頁面demo,信令交換過程手動操作

<!DOCTYPE html>
<html>
<head><title>WebRTC 文本消息發送</title>
</head>
<body><textarea id="xx"></textarea><textarea id="xx2"></textarea><textarea id="xx3"></textarea><div><label for="message">消息:</label><input type="text" id="message" /><button onclick="sendMessage()">發送</button><button onclick="sendOffer()">邀請</button><button onclick="handleAnswer()">接收遠程信令</button><button onclick="handleCandidate()">接收candidate</button><br><button onclick="handleOffer()">接收邀請</button></div><div id="chat"></div><script>let pc;let dataChannel;// 創建本地PeerConnection對象function createPeerConnection() {pc = new RTCPeerConnection();// 創建數據通道dataChannel = pc.createDataChannel('chat');// 監聽收到消息事件dataChannel.onmessage = event => {console.log(event.data)const message = event.data;displayMessage(message);};// 監聽連接狀態變化事件dataChannel.onopen = () => {displayMessage('連接已建立');};dataChannel.onclose = () => {displayMessage('連接已關閉');};pc.ondatachannel = (e)=>{console.log("ondatachannel",e)};// 監聽ICE候選事件pc.onicecandidate = e => {if (e.candidate) {document.getElementById("xx3").value = JSON.stringify(e.candidate);}};pc.oniceconnectionstatechange = e => {console.log('Local ICE connection state change:', pc.iceConnectionState);};}createPeerConnection()// 處理信令function handleSignal(signal) {switch (signal.type) {case 'offer':handleOffer(signal.offer);break;case 'answer':handleAnswer(signal.answer);break;case 'candidate':handleCandidate(signal.candidate);break;}}async function sendOffer(){let desc = await pc.createOffer()pc.setLocalDescription(desc); document.getElementById("xx").value = JSON.stringify(desc)console.log(desc)}// 處理Offer信令async function handleOffer() {await pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(document.getElementById("xx2").value)));let answer = await pc.createAnswer()await pc.setLocalDescription(answer);document.getElementById("xx").value = JSON.stringify(answer)}// 處理Answer信令async function handleAnswer() {// 設置遠端描述let answer = new RTCSessionDescription(JSON.parse(document.getElementById("xx2").value))await pc.setRemoteDescription(answer);}// 處理ICE候選信令async function handleCandidate() {try {await pc.addIceCandidate(new RTCIceCandidate(JSON.parse(document.getElementById("xx2").value)));} catch (error) {console.error('添加ICE候選失敗:', error);}}// 發送消息function sendMessage() {const messageInput = document.getElementById('message');const message = messageInput.value;dataChannel.send(message);displayMessage('我:' + message);messageInput.value = '';}// 顯示消息function displayMessage(message) {const chatDiv = document.getElementById('chat');const messageP = document.createElement('p');messageP.textContent = message;chatDiv.appendChild(messageP);}</script>
</body>
</html>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/167840.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/167840.shtml
英文地址,請注明出處:http://en.pswp.cn/news/167840.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Javaweb之前端工程化的詳細解析

3 前端工程化 3.1 前端工程化介紹 我們目前的前端開發中&#xff0c;當我們需要使用一些資源時&#xff0c;例如&#xff1a;vue.js&#xff0c;和axios.js文件&#xff0c;都是直接再工程中導入的&#xff0c;如下圖所示&#xff1a; 但是上述開發模式存在如下問題&#xff…

git的使用:本地git下載、sshkey的添加、github倉庫創建及文件上傳

一、github創建賬號 即github注冊賬號&#xff0c;登錄github官網&#xff0c;根據提示注冊即可 github官網 二、git客戶端下載安裝 已有很多git下載安裝的博文了&#xff0c;在此就不贅述 三、sshkey的生成與添加 1、sshkey的生成以及查看 // sshkey的生成命令&#xff…

OSS+CDN的資費和安全

文章目錄 花費OSSCDNOSS CDN 安全OSS防盜鏈跨域設置CORS數據加密 CDN防盜鏈URL鑒權Cookie鑒權遠程鑒權IP黑白名單UA黑白名單 回源服務自定義私有參數IP黑白名單數據加密 花費 OSS 存儲費用 &#xff1a;0.12元/GB/月下行流量費用 &#xff1a;0.5元/GB請求費用 &#xff1a;…

java全局異常處理(springboot)

介紹&#xff1a; 在日常項目開發中&#xff0c;異常是常見的&#xff0c;但是如何更高效的處理好異常信息&#xff0c;讓我們能快速定位到BUG&#xff0c;是很重要的&#xff0c;不僅能夠提高我們的開發效率&#xff0c;還能讓你代碼看上去更舒服&#xff0c;SpringBoot的項目…

C語言你愛我么?(ZZULIOJ 1205:你愛我么?)

題目描述 LCY買個n束花準備送給她暗戀的女生&#xff0c;但是他不知道這個女生是否喜歡他。這時候一個算命先生告訴他讓他查花瓣數&#xff0c;第一個花瓣表示"愛"&#xff0c;第二個花瓣表示"不愛"&#xff0c;第三個花瓣表示"愛"..... 為了使最…

某60區塊鏈安全之未初始化的存儲指針實戰二學習記錄

系列文章目錄 文章目錄 系列文章目錄未初始化的存儲指針實戰二實驗目的實驗環境實驗工具實驗原理實驗內容實驗過程EXP利用 未初始化的存儲指針實戰二 實驗目的 學會使用python3的web3模塊 學會分析以太坊智能合約未初始化的存儲指針漏洞 找到合約漏洞進行分析并形成利用 實驗…

機器學習之自監督學習(四)MoCo系列翻譯與總結(二)

MoCo中相關工作的對比分析 去噪自動編碼器&#xff08;Denoising Autoencoder&#xff09;是一種用于學習數據表示的神經網絡模型。它的主要目標是通過去除輸入數據中的噪聲&#xff0c;學習到輸入數據的有用表示&#xff0c;從而提高模型對干凈數據的魯棒性。下面是對去噪自動…

Flink 常用物理分區算子(Physical Partitioning)

Flink 物理分區算子(Physical Partitioning) 在Flink中&#xff0c;常見的物理分區策略有&#xff1a;隨機分配(Random)、輪詢分配(Round-Robin)、重縮放(Rescale)和廣播(Broadcast)。 接下來&#xff0c;我們通過源碼和Demo分別了解每種物理分區算子的作用和區別。 (1) 隨機…

win10安裝pytorch(py39)

cuda≤11.6&#xff0c;觀察控制面板 觀察torch對應cuda版本 https://download.pytorch.org/whl/torch/ 安裝cuda11.6.0 CUDA Toolkit Archive | NVIDIA Developer cmd輸入nvcc -V 編輯國內鏡像源 .condarc anaconda prompt輸入 查看環境 conda env list 安裝py3.9…

uniapp視頻倍速播放插件,uniapp視頻試看插件——sunny-video使用文檔

sunny-video視頻倍速播放器 組件名&#xff1a;sunny-video 效果圖 img1img2img3img4 平臺差異說明 目前已應用到APP&#xff08;安卓、iOS&#xff09;、微信&#xff08;小程序、H5&#xff09;其它平臺未測試 安裝方式 本組件符合easycom規范&#xff0c;HBuilderX 2.5…

emoji

圖標的網址&#xff1a; webfx emojipedia 1.可以直接復制粘貼 2.按照其格式文本表示&#xff08;Shortcodes&#xff09; &#x1f680; &#x1f604; &#x1f92b; ?? &#x1f480; 還有關于通過鏈接引用shield.io中的圖標&#xff0c;沒有深究&#xff0c;不…

第六十三周周報

學習目標&#xff1a; 項目 實驗和論文 學習時間&#xff1a; 2023.11.18-2023.11.24 學習產出&#xff1a; 論文 對論文進行了潤色和修改 實驗 1、上周DiffusionRelative的結果無法再次復現&#xff0c;新跑的FID與以前實驗跑的結果相差不大&#xff0c;上周的結果應…

點大商城V2.5.3分包小程序端+小程序上傳提示限制分包制作教程

這幾天很多播播資源會員反饋點大商城V2.5.3小程序端上傳時提示大小超限&#xff0c;官方默認單個包都不能超過2M&#xff0c;總分包不能超20M。如下圖提示超了93KB&#xff0c;如果出現超的不多情況下可采用手動刪除一些images目錄下不使用的圖片&#xff0c;只要刪除超過100KB…

鴻蒙4.0開發筆記之DevEco Studio如何使用低代碼開發模板進行開發的詳細流程(六)

鴻蒙低代碼開發 一、什么是低代碼二、如何進行鴻蒙低代碼開發1、 創建低代碼開發工程&#xff08;方式壹&#xff09;2、已有工程則創建Visual文件&#xff08;方拾貳&#xff09; 三、低代碼開發界面介紹四、低代碼實現頁面跳轉五、低代碼開發建議 一、什么是低代碼 所謂低代碼…

Qt+xml解析

文章目錄 一、xml文件介紹1.1 XML 文件結構和基本概念1.2 XML 文件示例二、Qt讀取xml文件2.1 Qt讀取xml 步驟2.2 基本操作和函數 QXmlStreamReader2.3 錯誤處理errorString和hasError2.4 Qt讀取xml實例三、實際項目一、xml文件介紹 1.1 XML 文件結構和基本概念 XML(可擴展標…

三、ts高級筆記,

文章目錄 18、d.ts聲明文件19、Mixin混入20、Decorator裝飾器的使用21、-高級proxy攔截_Reflect元儲存22、-高級寫法Partial-Pick23、Readonly只讀_Record套對象24、高階寫法Infer占位符25、Inter實現提取類型和倒敘遞歸26、object、Object、{}的區別27、localStorage封裝28、協…

基于 STM32F7 和神經網絡的實時人臉特征提取與匹配算法實現

本文討論了如何使用 STM32F7 和神經網絡模型來實現實時人臉特征提取與匹配算法。首先介紹了 STM32F7 的硬件和軟件特點&#xff0c;然后討論了人臉特征提取和匹配算法的基本原理。接下來&#xff0c;我們將重點討論如何在 STM32F7 上實現基于神經網絡的人臉特征提取與匹配算法&…

微機原理_3

一、單項選擇題(本大題共15小題,每小題3分,共45分。在每小題給出的四個備選項中,選出一個正確的答案,請將選定的答案填涂在答題紙的相應位置上。) 在 8086 微機系統中&#xff0c;完成對指令譯碼操作功能的部件是&#xff08;)。 A. EU B. BIU C. SRAM D. DRAM 使計算機執行某…

【機器學習】聚類(一):原型聚類:K-means聚類

文章目錄 一、實驗介紹1. 算法流程2. 算法解釋3. 算法特點4. 應用場景5. 注意事項 二、實驗環境1. 配置虛擬環境2. 庫版本介紹 三、實驗內容0. 導入必要的庫1. Kmeans類a. 構造函數b. 閔可夫斯基距離c. 初始化簇心d. K-means聚類e. 聚類結果可視化 2. 輔助函數3. 主函數a. 命令…

ElasticSearch之虛擬內存

查看當前Linux系統中vm.max_map_count變量的值&#xff0c;命令如下&#xff1a; sysctl vm.max_map_count執行結果的樣例&#xff0c;如下&#xff1a; vm.max_map_count 65530修改參數vm.max_map_count的值&#xff0c;命令如下&#xff1a; sysctl -w vm.max_map_count2…