WebRTC技術簡介及應用場景

寫在前面

本文是參考稀土掘金的文章,整理得出,版權歸原作者所有!

參考鏈接:https://juejin.cn/book/7168418382318927880/section/7171376753263247396

WebRTC(Web Real-Time Communication) 是一項開源技術,允許瀏覽器和移動應用直接進行實時音視頻通信數據傳輸,無需安裝插件或第三方軟件。它由 Google 發起,現已成為 W3C 和 IETF 的標準。

核心特點:

  1. 點對點(P2P)連接

    • 設備間直接通信,降低延遲,提升效率。

    • 但需通過?ICE/STUN/TURN?服務器解決 NAT 穿越問題。

  2. 無需插件

    • 原生支持主流瀏覽器(Chrome、Firefox、Safari 等)。

  3. 關鍵組件

    • MediaStream(getUserMedia):獲取攝像頭/麥克風數據。

    • RTCPeerConnection:建立音視頻傳輸連接。

    • RTCDataChannel:支持任意數據(如文件、游戲指令)傳輸。

  4. 安全加密

    • 強制使用?SRTP(音視頻加密)和?DTLS(數據加密)。

  5. 適應網絡變化

    • 自動調整碼率、抗丟包,適應不同網絡條件。

常見應用場景:

  • 視頻會議(如 Google Meet、Zoom 的網頁版)

  • 在線教育、遠程醫療

  • 文件共享、屏幕共享

  • 物聯網設備控制

攝像頭和麥克風屬于用戶的隱私設備,WebRTC既然成為了瀏覽器中音視頻即時通信的W3C標準,因此必然會提供API,讓有一定代碼開發能力的人去調用;

注意敲黑板:?使用這些API是有前提條件的哦,首先在安全源訪問,調用API才沒有任何阻礙的。那什么是安全源呢?看下面思維導圖(更詳細的看:chrome官方文檔),且記住這句話:安全源?是至少匹配以下( Scheme?、?Host?、?Port )模式之一的源

舉個簡單的例子:你本地開發用HTTP請求地址獲取攝像頭API沒有問題,但是你的同事用他的電腦訪問你電腦IP對應的項目地址時,攝像頭調用失敗,為什么呢?

因為在他的瀏覽器中,你的項目訪問地址非HTTPS,在非HTTPS的情況下,如果IP不是localhost127.0.0.1,都不屬于安全源

當然事非絕對,在特定情況下必須使用非HTTPS訪問也是可以的,Chrome提供了對應的取消限制但是不太建議用(安全為上),因此我在這里就不再多余闡述。

所以經常有人問,為什么我的代碼在自己瀏覽器中可以獲取到攝像頭,但是在區域網下別的電腦的瀏覽器中獲取不到?同樣的瀏覽器、同樣的操作系統,為什么獲取不到呢?原因就是上面的安全源限制。

getUserMedia?

以前的版本中我們經常使用?navigator.getUserMedia?來獲取計算機的攝像頭或者麥克風,但是現在這個接口廢棄,變更為?navigator.mediaDevices.getUserMedia,因此后面我們均使用新的API來完成代碼編寫。

getUserMedia可以干什么?

意如其名,那就是獲取用戶層面的媒體,當你的計算機通過?USB?或者其他網絡形式接入了?N 多個攝像頭或虛擬設備時,都是可以通過這個?API?獲取到的。 當然不僅僅是視頻設備,還包括音頻設備和虛擬音頻設備。?獲取媒體設備是最簡單的操作,它還可以控制獲取到媒體的分辨率,以及其他的以一些可選項。

PS:在很多云會議中,我們開會只能選擇一個攝像頭,這并不是只能使用一個攝像頭,而是廠商針對“大多數場景中只會用到一個攝像頭”而設計的;但在有些業務中,我們可能需要自己設備上的N 個攝像頭(帶USB攝像頭)同時使用,那么如何辦到呢(這個場景其實蠻多的,后面留個課后題)。因此熟知這個?API?對于解決基本的會議和其他復雜場景問題很有用。

如何使用?getUserMedia

有簡單的用法,有復雜的用法。一般簡易場景下,大多數 API 用默認參數就可以實現對應功能,getUserMedia也一樣,直接調用不使用任何參數,則獲取的就是 PC 的默認攝像頭和麥克風。

但是,當我們遇到復雜一點的應用場景,比如你的電腦上自帶麥克風,同時你連接了藍牙耳機和有線耳機,那么在視頻通話過程中,你如何主動選擇使用哪個呢?也就是說,?在用攝像頭或者麥克風之前,我們先要解決如何從?N 個攝像頭或者麥克風中選擇我們想要的。

要解決這個問題,我們必須先有個大體的思路(當然這個思路并不是憑空想象出來的,而是在一定的技術儲備下才有的。如果你開始前沒有任何思路也沒關系,可以參考他人的經驗),如下:

  1. 獲取當前設備所有的攝像頭和麥克風信息;

  1. 從所有的設備信息中遍歷篩選出我們想要使用的設備;

  1. 將我們想要使用的設備以某種參數的形式傳遞給瀏覽器?API

  1. 瀏覽器API去執行獲取的任務。

上面提到的設備以某種參數的形式傳遞給?API,那么這個設備必然是以參數存在的,因此這里有幾個概念需要提前知道,如下:

設備分成了圖中的三個大類型,每個類型都有固定的字段,比如?ID、kind、label?,而其中用于區分它們的就是kind字段中的固定值最核心的字段就是 ID,后面我們經常用的就是這個 ID。

那么,在前端如何使用?JavaScript獲取到這些信息?

大家先看下面這段代碼,大體上過一遍,并留意?initInnerLocalDevice函數內部執行順序。

function handleError(error) {alert("攝像頭無法正常使用,請檢查是否占用或缺失")console.error('navigator.MediaDevices.getUserMedia error: ', error.message, error.name);
}
/*** @author suke* device list init */
function initInnerLocalDevice(){const that  = thisvar localDevice = {audioIn:[],videoIn: [],audioOut: []}let constraints = {video:true, audio: true}if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {console.log("瀏覽器不支持獲取媒體設備");return;}navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {stream.getTracks().forEach(trick => {trick.stop()})// List cameras and microphones.navigator.mediaDevices.enumerateDevices().then(function(devices) {devices.forEach(function(device) {let obj = {id:device.deviceId, kind:device.kind, label:device.label}if(device.kind === 'audioinput'){if(localDevice.audioIn.filter(e=>e.id === device.deviceId).length === 0){localDevice.audioIn.push(obj)}}if(device.kind === 'audiooutput'){if(localDevice.audioOut.filter(e=>e.id === device.deviceId).length === 0){localDevice.audioOut.push(obj)}}else if(device.kind === 'videoinput' ){if(localDevice.videoIn.filter(e=>e.id === device.deviceId).length === 0){localDevice.videoIn.push(obj)}}});}).catch(handleError);}).catch(handleError);}

這個代碼片段的主要作用就是獲取用戶設備上所有的攝像頭和麥克風信息,起關鍵作用的是enumerateDevices函數,但是在調用這個關鍵函數之前,getUserMedia函數出現在了這里,它的出現是用戶在訪問服務時直接調用用戶攝像頭,此時如果用戶授權且同意使用設備攝像頭、麥克風,那么enumerateDevices函數就能獲取設備信息了,在這里getUserMedia函數可以理解為獲取攝像頭或者麥克風權限集合的探路函數

看下圖,我將我電腦上使用enumerateDevices函數加載到的信息,根據前面提到的字段kind,將其分三類并打印到控制臺。

千萬不要小看現在獲取到的這些信息哦,在后面視頻通話或會議過程中,我們需要抉擇攝像頭用前置還是后置,麥克風是用藍牙還是有線,都是離不開這些信息的。

在拿到所有的攝像頭麥克風信息之后,我們需選出最終要參與視頻通話的那個信息體,看上圖中?VideoIn數組里面label:"eseSoft Vcam"??這個攝像頭就是我想要參會的攝像頭,那么我怎樣指定讓代碼去選擇這個攝像頭呢?這里就涉及到了getUserMedia的約束參數constraints?。

媒體約束 constraints

在具體講解約束參數 constraints 之前,大家先看下面這段示例代碼。

let constraints = {video:true, audio: true} function handleError(error) {console.error('navigator.MediaDevices.getUserMedia error: ', error.message, error.name);}/*** 獲取設備 stream* @param constraints* @returns {Promise<MediaStream>}*/async function getLocalUserMedia(constraints){return await navigator.mediaDevices.getUserMedia(constraints)}let stream = await this.getLocalUserMedia(constraints).catch(handleError);
console.log(stream)

上面的代碼片段為JavaScript獲取計算機攝像頭和麥克風的媒體流(視頻和音頻流我們統稱為媒體流)的一種方式,大多數情況下都是這么用的,如果電腦有攝像頭、麥克風,這樣獲取沒有任何問題,但就擔心你用的時候,你的電腦上沒有配攝像頭或麥克風,或者有多個攝像頭而你想指定其中某一個。?為了兼容更多情況,我們需要知道constraints這個參數的詳細用法。

接下來我們看下這個參數在幾種常見場景下的具體配置,以及為什么這樣配置。

1.同時獲取視頻和音頻輸入

使用下面約束, 如果遇到計算機沒有攝像頭的話,你調用上述代碼的過程中就會報錯,因此我們在調用之前可以通過enumerateDevices返回結果主動判斷有無視頻輸入源,沒有的話,可以動態將這個參數中的?video設置為false

{ audio: true, video: true }

2.獲取指定分辨率

在會議寬帶足夠且流媒體傳輸合理的情況下,無需考慮服務端壓力,而需考慮客戶端用戶攝像頭的分辨率范圍,通常我們會設置一個分辨率區間。

下面展示的①約束是請求一個?1920×1080?分辨率的視頻,但是還提到?min?參數,將?320×240?作為最小分辨率,因為并不是所有的網絡攝像頭都可以支持?1920×1080?。當請求包含一個?ideal(應用最理想的)值時,這個值有著更高的權重,意味著瀏覽器會先嘗試找到最接近指定理想值的設定或者攝像頭(如果設備擁有不止一個攝像頭)。

但是,在多人會議簡單架構場景中,在不改變會議穩定性的情況下,為了讓更多的客戶端加入,我們通常會把高分辨率主動降低到低分辨率,約束特定攝像頭獲取指定分辨率如下面②配置。

--------------------①:1--------------------------{audio: true,video: {width: { min: 320, ideal: 1280, max: 1920 },height: { min: 240, ideal: 720, max: 1080 }}}--------------------②:2--------------------------{audio: true,video: { width: 720, height: 480}
}

3.指定視頻軌道約束:獲取移動設備的前置或者后置攝像頭

facingMode屬性。可接受的值有:user(前置攝像頭)、environment(后置攝像頭);需要注意的是,這個屬性在移動端可用,當我們的會議項目通過 h5 在移動端打開時,我們可以動態設置這個屬性從而達到切換前后攝像頭的場景。

{ audio: true, video: { facingMode: "user" } }
{ audio: true, video: { facingMode: { exact: "environment" } } }

?4.定幀速率frameRate

幀速率(你可以理解為FPS)不僅對視頻質量,還對帶寬有著影響,所以在我們通話過程中,如果判定網絡狀況不好,那么可以限制幀速率。

我們都知道,視頻是通過一定速率的連續多張圖像形成的,比如每秒 24 張圖片才會形成一個基礎流暢的視頻,因此幀速率對于實時通話的質量也有影響,你可以想象成和你的游戲的FPS一個道理。

const constraints = {audio: true,video: {width:1920,height:1080,frameRate: { ideal: 10, max: 15 }}
};

實際上,通過FPS我們可以引申出來一些場合,在特定場合選擇特定的FPS搭配前面的分辨率配置,以提高我們會議系統的質量,比如:

  • 屏幕分享過程中,我們應當很重視高分辨率而不是幀速率,稍微卡點也沒關系;
  • 在普通會議過程中,我們應當重視的是畫面的流暢,即幀速率而不是高分辨率;
  • 在開會人數多但寬帶又受限的情況下,我們重視的同樣是會議的流程性,同樣低分辨率更適合寬帶受限的多人會議;
  • ……

5.使用特定的網絡攝像頭或者麥克風

重點哦,我們最前面enumerateDevices函數獲取到的設備集合可以派上用場了。

/*** 獲取指定媒體設備id對應的媒體流* @author suke* @param videoId* @param audioId* @returns {Promise<void>}*/
async function getTargetIdStream(videoId,audioId){const constraints = {audio: {deviceId: audioId ? {exact: audioId} : undefined},video: {deviceId: videoId ? {exact: videoId} : undefined,width:1920,height:1080,frameRate: { ideal: 10, max: 15 }}};if (window.stream) {window.stream.getTracks().forEach(track => {track.stop();});}//被調用方法前面有,此處不再重復let stream = await this.getLocalUserMedia(constraints).catch(handleError);}

getDisplayMedia

我們日常開會,多數需要通過會議 App 來分享自己的屏幕,或者僅分享桌面上固定的應用程序那么在瀏覽器中實現視頻通話,能否實現分享屏幕呢?答案是肯定的,?W3C的?Screen Capture?標準中有說明,就是使用getDisplayMedia

var promise = navigator.mediaDevices.getDisplayMedia(constraints);## 獲取屏幕分享
navigator.mediaDevices.getDisplayMedia(constraints).then((stream) => {/* use the stream */}).catch((err) => {/* handle the error */});

參數 Constraints

同上一個函數一樣,同樣需要配置constraints約束,當然這個也是可選的, 如果選擇傳參的話,那么參數設置如下:

getDisplayMedia({audio: true,video: true
})

但是這里的constraints配置和前面getUserMedia的約束配置是有差別的。又一個重點來了,在屏幕分享的約束中,video?是不能設置為false?的,但是可以設置指定的分辨率,如下:

getDisplayMedia({audio: true,video: {width:1920,height:1080}
})
  1. audiotrue

  2. audiofalse

?請留意上面兩圖的對比,當去掉音頻后,第二張圖少了個勾選系統音頻的 radio 框。

完整案例

/*** 獲取屏幕分享的媒體流* @author suke* @returns {Promise<void>}*/
async function getShareMedia(){const constraints = {video:{width:1920,height:1080},audio:false};if (window.stream) {window.stream.getTracks().forEach(track => {track.stop();});}return await navigator.mediaDevices.getDisplayMedia(constraints).catch(handleError);
}

小提示

  • 在前面的案例代碼中,我們在獲取系統的音頻或者視頻的stream之前,一般會調用以下代碼,目的是清除當前標簽頁中沒有銷毀的媒體流。 ??
       if (window.stream) {window.stream.getTracks().forEach(track => {track.stop();});}
    

    如果不銷毀,你可以看到在標簽頁旁邊一直有個小紅圈閃爍,鼠標按上去提示正在使用當前設備的攝像頭,因此在后面的開發中保持好習慣:結束自己會議后或頁面用完攝像頭后,一般除了強制刷新,也可以調用上面代碼清除正在使用的stream調用。

    好了,這節課我們我們掌握了兩個最重要的 API,下節課我們開始搭建一個信令服務器,同時完成?P2P?(單人對單人)的視頻通話(跑代碼的時候一定要記得前面提到的安全源哦)。

檢測函數

githup上檢測webRtc鏈接:Select audio and video sources

靜默基礎檢測

function isSupportWebRtcFlag() {// 獲取用戶代理字符串,用于檢測瀏覽器類型const userAgent = navigator.userAgent,isIphone = userAgent.indexOf('iPhone') > -1,isUcBrowser = userAgent.indexOf('UCBrowser') > -1,isIphoneUC = isIphone && isUcBrowser;let canIUseDataChannel = true,canIUseRTCPeer = true,canIUseGetUserMedia = false,canIUseRealTime = false;// 檢測是否支持 getUserMedia(獲取設備列表)if (navigator.mediaDevices&& navigator.mediaDevices.getUserMedia|| navigator.getUserMedia|| navigator.mozGetUserMedia|| navigator.mozGetUserMedia) {canIUseGetUserMedia = true;}// 檢測是否支持 RTCPeerConnection (數據通道)canIUseRTCPeer = Boolean(window.RTCPeerConnection)|| Boolean(window.webkitRTCPeerConnection)|| Boolean(window.mozRTCPeerConnection)|| Boolean(window.msRTCPeerConnection)|| Boolean(window.oRTCPeerConnection);try {const o = new (window.RTCPeerConnection || window.msRTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection)(null);// eslint-disable-next-line no-restricted-syntaxcanIUseDataChannel = 'createDataChannel' in o;} catch (e) {console.error('嘗試創建 RTCPeerConnection 對象,以檢測是否支持數據通道錯誤,error:', e);canIUseDataChannel = false;}// 綜合判斷是否支持所有 WebRTC 功能canIUseRealTime = canIUseGetUserMedia && canIUseRTCPeer && canIUseDataChannel && !isIphoneUC;if (!canIUseGetUserMedia) {console.warn('webRtcUtils[isSupportWebRtcFlag] --> 不支持getUserMedia');}if (!canIUseRTCPeer) {console.warn('webRtcUtils[isSupportWebRtcFlag] --> 不支持RTCPeerConnection');}if (!canIUseDataChannel) {console.warn('webRtcUtils[isSupportWebRtcFlag] --> 不支持createDataChannel');}if (canIUseRealTime) {console.info('webRtcUtils[isSupportWebRtcFlag] --> 支持炫彩api');} else {console.warn('webRtcUtils[isSupportWebRtcFlag] --> 不支持炫彩api');}return {canIUseGetUserMedia,canIUseRTCPeer,canIUseDataChannel,canIUseRealTime};
}isSupportWebRtcFlag();

靜默黑名單檢測

function isSupportWebRtcSilently() {const ua = navigator.userAgent;const isMobile = (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i).test(ua);// 1. 檢測關鍵 API 是否存在const hasGetUserMedia = Boolean(navigator.mediaDevices?.getUserMedia|| navigator.getUserMedia|| navigator.webkitGetUserMedia|| navigator.mozGetUserMedia);const hasRTCPeerConnection = Boolean(window.RTCPeerConnection|| window.webkitRTCPeerConnection|| window.mozRTCPeerConnection);// 2. 檢測 DataChannel 支持let hasDataChannel = false;if (hasRTCPeerConnection) {try {const pc = new (window.RTCPeerConnection || window.webkitRTCPeerConnection)({iceServers: []});// eslint-disable-next-line no-restricted-syntaxhasDataChannel = 'createDataChannel' in pc;pc.close();} catch (e) {console.error('檢測 DataChannel 支持', e);hasDataChannel = false;}}// 3. 排除已知有問題的瀏覽器或場景const isBlockedBrowser// 排除 UC 瀏覽器、QQ 瀏覽器、MIUI 瀏覽器等= (/UCBrowser|QQBrowser|MiuiBrowser|Quark|baiduboxapp/i).test(ua)// iOS 第三方瀏覽器(如 Firefox Focus)可能限制 WebRTC|| isMobile && (/Firefox/i).test(ua) && !(/FxiOS/).test(ua);// 4. 綜合判斷const isSupported= hasGetUserMedia&& hasRTCPeerConnection&& hasDataChannel&& !isBlockedBrowser;const result = {isSupported,details: {hasGetUserMedia,hasRTCPeerConnection,hasDataChannel,isBlockedBrowser}};	console.info('--result--', result);return result;
}
isSupportWebRtcSilently();

精準檢測 (需用戶授權)

async function preciseWebRTCSupportCheck() {const result = {supportsWebRTC: false,details: {hasRTCPeerConnection: false,hasDataChannel: false,hasGetUserMedia: false,hasIceSupport: false,hasCodecSupport: { video: [], audio: [] },errors: []}};try {// 1. 檢測 RTCPeerConnection 和 DataChannelconst RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;if (!RTCPeerConnection) {result.details.errors.push('RTCPeerConnection API missing');return result;}result.details.hasRTCPeerConnection = true;const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });result.details.hasDataChannel = 'createDataChannel' in pc;// 2. 檢測 ICE 支持(網絡穿透)let hasIce = false;pc.onicecandidate = (e) => {if (e.candidate && e.candidate.candidate) {hasIce = true;result.details.hasIceSupport = true;}};// 3. 檢測編解碼器支持(H.264/VP8/Opus)const sender = pc.addTransceiver('video');const capabilities = sender.sender.getCapabilities();result.details.hasCodecSupport.video = capabilities.codecs.filter(c => c.mimeType.includes('video'));result.details.hasCodecSupport.audio = capabilities.codecs.filter(c => c.mimeType.includes('audio'));// 4. 實際創建 Offer 以觸發 ICE 收集const offer = await pc.createOffer();await pc.setLocalDescription(offer);// 等待 ICE 收集完成(最多 2 秒)await new Promise(resolve => setTimeout(resolve, 2000));pc.close();// 5. 檢測 getUserMedia(需用戶授權)if (navigator.mediaDevices?.getUserMedia) {try {const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });stream.getTracks().forEach(track => track.stop());result.details.hasGetUserMedia = true;} catch (e) {result.details.errors.push(`getUserMedia failed: ${e.name}`);}}// 綜合判定result.supportsWebRTC = (result.details.hasRTCPeerConnection &&result.details.hasDataChannel &&result.details.hasIceSupport &&result.details.hasGetUserMedia &&result.details.hasCodecSupport.video.length > 0);} catch (e) {result.details.errors.push(`Critical error: ${e.message}`);}return result;
}

?

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

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

相關文章

Windows 圖形顯示驅動開發-WDDM 2.1 功能(四)

驅動程序版本控制 圖形適配器或芯片集的驅動程序 DLL 和 SYS 文件必須具有正確格式的文件版本。 驅動程序信息文件 (.inf)、內核模式驅動程序 (.sys) 和用戶模式驅動程序 (.dll) 文件的版本信息必須一致。 此外&#xff0c;.inf 的 [SignatureAttributes] 部分中標識為 PETru…

什么是 StarRocks?核心優勢與適用場景解析

在數據量持續爆發的時代&#xff0c;企業對實時分析的需求日益迫切。例如&#xff0c;電商大促期間的交易監控、廣告投放效果的即時反饋等場景&#xff0c;均要求毫秒級的響應速度。然而&#xff0c;傳統工具如 Hadoop、Hive 等存在明顯短板&#xff1a;復雜查詢性能不足、資源…

Java基礎 4.3

1.對象機制練習 public class Object03 {public static void main(String[] args) {Person a new Person();a.age 10;a.name "小明";Person b;b a;System.out.println(b.name);//小明b.age 200;b null;System.out.println(a.age);//200System.out.println(b.a…

視頻設備軌跡回放平臺EasyCVR綜合智能化,搭建運動場體育賽事直播方案

一、背景 隨著5G技術的發展&#xff0c;體育賽事直播迎來了新的高峰。無論是NBA、西甲、英超、德甲、意甲、中超還是CBA等熱門賽事&#xff0c;都是值得記錄和回放的精彩瞬間。對于體育迷來說&#xff0c;選擇觀看的平臺眾多&#xff0c;但是作為運營者&#xff0c;搭建一套體…

搬磚--貪心+排序的背包

a在上面b在下面->a.v-M-b.m>b.v-M-a.m->剩余率大 所以我先遍歷a&#xff0c;讓a在上面 這就是要考慮貪心排序的01背包 因為它有放的限制條件 #include<bits/stdc.h> using namespace std; #define N 100011 typedef long long ll; typedef pair<ll,int>…

《2024年全球DDoS攻擊態勢分析》

從攻擊態勢來看&#xff0c;2024年DDoS攻擊頻次繼續呈增長趨勢&#xff0c;2024年同步增加1.3倍&#xff1b;超大規模攻擊激增&#xff0c;超800Gbps同比增長3.1倍&#xff0c;累計高達771次&#xff0c;且互聯網史上最大帶寬和最大包速率攻擊均被刷新&#xff1b;瞬時泛洪攻擊…

數據分析參考架構詳解

1.數倉方法論 2. 數倉建模參考架構 3.大數據參考架構 4.數據分析參考架構

領馭科技:以微軟Azure Speech技術為核心,驅動翻譯耳機新時代

在全球化的今天&#xff0c;語言不再是溝通的障礙。領馭科技&#xff0c;作為微軟的核心合作伙伴&#xff0c;正引領翻譯耳機行業進入一個全新的發展階段。以時空壺與貿人為例&#xff0c;這兩家公司的翻譯耳機產品憑借其內置的微軟Azure Speech人工智能語音技術&#xff0c;為…

seaweedfs分布式文件系統

seaweedfs https://github.com/seaweedfs/seaweedfs.git go mod tidy go -o bin ./… seaweed占不支持smb服務&#xff0c;只能用fuse的方式mount到本地文件系統 weed master 默認端口&#xff1a;9333&#xff0c;支持瀏覽器訪問 weed volume 默認端口&#xff1a;8080 weed …

說清楚單元測試

在團隊中推行單元測試的時候,總是會被成員問一些問題: 這種測試無法測試數據庫的SQL(或者是ORM)是否執行正確?這種測試好像沒什么作用?關聯的對象要怎么處理呢?…借由本篇,來全面看一看單元測試。 單元測試是軟件開發中一種重要的測試方法,其核心目的是驗證代碼的最小…

服務器磁盤io性能監控和優化

服務器磁盤io性能監控和優化 全文-服務器磁盤io性能監控和優化 全文大綱 磁盤IO性能評價指標 IOPS&#xff1a;每秒IO請求次數&#xff0c;包括讀和寫吞吐量&#xff1a;每秒IO流量&#xff0c;包括讀和寫 磁盤IO性能監控工具 iostat&#xff1a;監控各磁盤IO性能&#xff0c…

辦公設備管理系統(springboot+ssm+jsp+maven)

基于springboot的辦公設備管理系統(springbootssmjspmaven) 系統功能主要有&#xff1a; 歡迎頁賬號管理 管理員賬號管理系統賬號添加密碼修改 普通管理員管理 用戶管理用戶添加用戶查詢 資產類型管理資產信息管理資產檔案管理資產報表

【STM32設計】基于STM32的智能門禁管理系統(指紋+密碼+刷卡+蜂鳴器報警)(代碼+資料+論文)

本課題為基于單片機的智能門禁系統&#xff0c;整個系統由AS608指紋識別模塊&#xff0c;矩陣鍵盤&#xff0c;STM32F103單片機&#xff0c;OLED液晶&#xff0c;RFID識別模塊&#xff0c;繼電器&#xff0c;蜂鳴器等構成&#xff0c;在使用時&#xff0c;用戶可以錄入新的指紋…

Java學習總結-io流-字節流

io的體系&#xff1a; FlieInputStream(文件字節輸入流) 是什么&#xff1a;磁盤以字節的形式輸入到內存中。 由于不同格式編碼長度&#xff0c;每次讀取一個或幾個字節&#xff0c;都有可能出現亂碼。 所以官方提供了&#xff0c;一次性讀入全部字節&#xff0c;以數組的形式…

玩轉JUC - 如何優雅的異步處理任務

1、概述 前面我們學習了并發包中的一些核心的基礎類&#xff0c;包括原子類、Lock 、以及線程間通信的一些工具類&#xff0c;相信你已經能夠正確的處理線程同步的問題了&#xff0c;今天我們繼續學習并發包下的工具類&#xff0c;我們本次主要學習線程池和異步計算框架相關的內…

MINIQMT學習課程Day2

如何和聚寬進行綁定交易 目前市場上的方式主要為以下三種方案&#xff1a; 1.聚寬和一創直接綁定&#xff08;現在已經被廢除&#xff09; 2.通過蔣老師所提出的redis方案&#xff0c;進行交易 3.李興果的&#xff0c;網頁發送到服務器數據庫&#xff0c;然后本地讀取數據進行…

【AI視頻】度加視頻測試

目標 前邊&#xff0c;大藏經用AI翻譯成功了&#xff0c;語音也生成了&#xff0c;就想著生成視頻了&#xff0c;然后就發現了這個寶藏工具。 先說結果&#xff1a;速度不是很快&#xff0c;出錯了&#xff0c;提示也不是很清晰&#xff0c;雖然不順利&#xff0c;但過程還是…

SAP CEO引領云端與AI轉型

在現任首席執行官克里斯蒂安克萊因&#xff08;Christian Klein&#xff09;的領導下&#xff0c;德國軟件巨頭 SAP 正在經歷一場深刻的數字化轉型&#xff0c;重點是向云計算和人工智能方向發展。他提出的戰略核心是“RISE with SAP”計劃&#xff0c;旨在幫助客戶從傳統本地部…

《系統分析師-基礎篇-1-6章總結》

第1章 緒論 系統分析師角色 職責&#xff1a;需求分析、系統設計、項目管理、技術協調。 能力要求&#xff1a;技術深度&#xff08;架構設計、開發方法&#xff09; 業務理解&#xff08;企業流程、行業知識&#xff09; 溝通能力。 系統開發生命周期 傳統模型&#xf…

HCIP-12 中間系統到中間系統基礎

HCIP-12 中間系統到中間系統基礎 一、ISIS的區域 1.管理區域&#xff1a;Area ID&#xff08;基于路由器的管理區域&#xff09; 2.算法區域 骨干區域&#xff1a;由連續的L2或者L1/2路由器組成的邏輯區域 非骨干區域&#xff1a;是由連續的L1或者L1/2路由器組成的邏輯區域…