【一文讀懂】WebRTC協議

WebRTC(Web Real-Time Communication)協議

WebRTC(Web Real-Time Communication)是一種支持瀏覽器和移動應用程序之間進行 實時音頻、視頻和數據通信 的協議。它使得開發者能夠在瀏覽器中實現高質量的 P2P(點對點)實時通信,而無需安裝插件或第三方軟件。WebRTC 主要用于視頻通話、語音聊天、在線協作和數據傳輸等應用場景。

核心功能

WebRTC 提供了以下幾個關鍵功能:

  1. 音視頻通信:WebRTC 支持通過瀏覽器進行音頻和視頻的實時傳輸,用戶之間可以進行高質量的語音和視頻通話。
  2. P2P 數據傳輸:WebRTC 不僅支持音視頻流,還支持點對點的數據通道(Data Channel)傳輸,適合進行文件傳輸、屏幕共享和實時協作。
  3. 低延遲:WebRTC 專門優化了數據傳輸過程,以減少通信中的延遲,使得實時通信更加順暢。

工作原理

WebRTC 使用了一系列底層協議和技術來實現點對點通信。WebRTC 的工作流程通常包括以下幾個關鍵步驟:

  1. 建立連接(Signaling)
    • 在 WebRTC 中,信令(Signaling) 是客戶端用于交換通信所需的元數據(如網絡信息、音視頻編解碼信息、媒體能力等)的一種過程。信令不是 WebRTC 協議的一部分,但它是 WebRTC 通信的必要步驟。
    • 信令的內容包括:協商媒體(音視頻)格式、網絡路徑、設備信息等。
    • 通常,信令使用 WebSockets、HTTP 或其他協議進行實現。
    • 信令過程包括:
      • Offer(提議):發起方創建會話請求,發送給接收方。
      • Answer(應答):接收方回應發起方的請求,確認會話設置。
      • ICE candidates(ICE 候選者):每個端點通過收集網絡候選地址來交換,以幫助建立最佳的 P2P 連接。
  2. 網絡連接(ICE、STUN 和 TURN)
    • ICE(Interactive Connectivity Establishment):用于在 NAT 后的網絡環境中建立端到端的連接。ICE 是 WebRTC 連接的關鍵組成部分,它幫助客戶端發現并連接到彼此。
    • STUN(Session Traversal Utilities for NAT):STUN 服務器幫助客戶端了解自己在 NAT 后的公網 IP 地址。
    • TURN(Traversal Using Relays around NAT):TURN 服務器在 P2P 連接無法直接建立時提供數據轉發服務,確保通信的可靠性。TURN 作為最后的解決方案,通常會導致更高的延遲,因此只有在需要時才使用。
  3. 媒體流傳輸(RTP/RTCP)
    • RTP(Real-Time Transport Protocol):RTP 是 WebRTC 用于音頻和視頻流的傳輸協議。它允許在網絡中實時地傳輸數據包,并為這些數據包添加時間戳,確保音視頻數據的正確順序。
    • RTCP(Real-Time Control Protocol):RTCP 用于監控 RTP 會話的質量,并提供流控制和同步。
  4. 數據傳輸(DataChannel)
    • RTCDataChannel:WebRTC 支持數據通道(DataChannel),使得瀏覽器間可以通過 P2P 傳輸任意數據(包括文本、文件、圖像等)。數據通道提供了低延遲的點對點數據傳輸能力,常用于文件傳輸、屏幕共享等應用。

關鍵技術

WebRTC 由多種技術組成,其中最重要的包括:

  1. getUserMedia:用于獲取用戶的音頻和視頻輸入設備(如麥克風和攝像頭)的權限。它會返回一個包含音視頻流的對象。

    navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {// 顯示視頻流const videoElement = document.getElementById('my-video');videoElement.srcObject = stream;}).catch(error => console.log('Error accessing media devices: ', error));
    
  2. RTCPeerConnection:用于建立、維護和管理 P2P 連接。它負責處理網絡連接、音視頻編解碼、帶寬管理等任務。

    const peerConnection = new RTCPeerConnection(configuration);
    peerConnection.addStream(localStream); // 添加本地音視頻流// 建立連接后,發送媒體流
    peerConnection.createOffer().then(offer => peerConnection.setLocalDescription(offer)).then(() => {// 將 offer 發送給接收方});
    
  3. RTCDataChannel:用于建立點對點的數據傳輸通道,可以傳輸任意類型的數據。

    javascript復制編輯const dataChannel = peerConnection.createDataChannel('chat');
    dataChannel.onopen = () => console.log('Data channel open');
    dataChannel.onmessage = (event) => console.log('Received message: ', event.data);// 發送數據
    dataChannel.send('Hello, WebRTC!');
    

應用場景

  1. 視頻通話:WebRTC 可以用于構建視頻會議應用,如 Zoom、Google Meet 等。
  2. 語音通話:WebRTC 支持語音通話,廣泛應用于 IP 電話、語音助手等。
  3. 文件傳輸:通過 RTCDataChannel,WebRTC 可以用于點對點的文件傳輸。
  4. 實時協作:WebRTC 用于多人在線編輯、白板共享等實時協作工具。
  5. 直播:WebRTC 可以支持低延遲的視頻直播,適用于游戲直播、網絡教學等領域。

實現過程

1. 獲取音視頻流(getUserMedia)

getUserMedia 是 WebRTC 中用于訪問用戶音頻和視頻設備的 API。通過它,你可以獲取麥克風和攝像頭的權限,從而獲取用戶的音視頻流。

示例:獲取視頻和音頻流
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {// 獲取視頻流后,可以將其顯示在視頻標簽上const videoElement = document.getElementById('localVideo');videoElement.srcObject = stream;// 創建 RTCPeerConnection 實例(將在后面討論)const peerConnection = new RTCPeerConnection();// 將本地流添加到連接stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));}).catch(error => {console.error('Error accessing media devices.', error);});
  • getUserMedia:請求用戶設備的音視頻流。
  • 返回的 MediaStream 可以用于顯示、錄制或傳輸。
2. 創建點對點連接(RTCPeerConnection)

WebRTC 使用 RTCPeerConnection 來管理媒體流的傳輸。它代表了與另一個客戶端的點對點連接。

示例:創建 RTCPeerConnection 并添加本地流
const peerConnection = new RTCPeerConnection({iceServers: [{ urls: 'stun:stun.l.google.com:19302' } // 使用 STUN 服務器]
});// 添加本地流到連接
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {const localVideo = document.getElementById('localVideo');localVideo.srcObject = stream;stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));});
  • STUN 服務器:STUN(Session Traversal Utilities for NAT)幫助客戶端發現自己的公共 IP 地址,用于 NAT 穿透。
3. 信令交換(Signal)

WebRTC 協議并不直接定義信令交換的方式,因此你需要自己實現信令交換。信令過程用于交換連接的元數據,如會話描述(SDP)和 ICE 候選者等。

  1. 創建 Offer(發起方)
peerConnection.createOffer().then(offer => {return peerConnection.setLocalDescription(offer);  // 設置本地 SDP}).then(() => {// 將 offer 發送給對方(通過信令服務器)signalingServer.send({ type: 'offer', offer: peerConnection.localDescription });});
  • SDP(Session Description Protocol):描述了音視頻流的編碼、傳輸等信息。
  1. 設置 Answer(接收方)

接收方收到 Offer 后,創建 Answer 并回復:

signalingServer.on('offer', offer => {peerConnection.setRemoteDescription(new RTCSessionDescription(offer)).then(() => peerConnection.createAnswer()).then(answer => {return peerConnection.setLocalDescription(answer);  // 設置本地 SDP}).then(() => {// 將 answer 發送給發起方signalingServer.send({ type: 'answer', answer: peerConnection.localDescription });});
});
  1. 交換 ICE 候選者

在連接過程中,客戶端會收集并交換 ICE 候選者(候選網絡路徑)。這些候選者用于尋找最佳的連接路徑。

peerConnection.onicecandidate = event => {if (event.candidate) {// 發送 ICE 候選者到對方signalingServer.send({ type: 'ice-candidate', candidate: event.candidate });}
};// 接收對方的 ICE 候選者
signalingServer.on('ice-candidate', candidate => {peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
});
  1. 建立連接并處理媒體流

當信令交換完成并且 ICE 候選者交換完畢后,WebRTC 將會建立一個完整的點對點連接,音視頻流會開始傳輸。

示例:顯示遠端視頻流

peerConnection.ontrack = event => {const remoteVideo = document.getElementById('remoteVideo');remoteVideo.srcObject = event.streams[0];  // 獲取遠程流并顯示
};

5. 數據通道(RTCDataChannel)

WebRTC 還支持 RTCDataChannel,用于在兩個客戶端之間進行低延遲的點對點數據傳輸(例如文件傳輸、聊天信息等)。

示例:創建并使用數據通道
const dataChannel = peerConnection.createDataChannel('chat');// 監聽數據通道的消息
dataChannel.onmessage = event => {console.log('Received message:', event.data);
};// 發送數據
dataChannel.send('Hello from WebRTC!');

6. 斷開連接

當通信結束時,你可以通過關閉 PeerConnection 來斷開連接并釋放資源。

peerConnection.close();

WebRTC-Streamer開源項目

項目介紹

WebRTC-Streamer 是一個開源工具集,旨在簡化實時音視頻數據流的傳輸與集成,主要通過 WebRTC 技術實現低延遲的音視頻流傳輸。開發者無需深入理解復雜的底層協議即可輕松將實時音視頻功能集成到自己的應用中。該項目特別設計了高效的音視頻流處理功能,支持多種數據來源,如 V4L2 捕獲設備RTSP 流屏幕捕捉 等,適用于多種實時傳輸場景。

快速啟動

WebRTC-Streamer 提供了簡便的集成方式。以下是一個通過 HTML 和 JavaScript 快速搭建基本實時音視頻流服務的示例代碼:

<html>
<head><script src="libs/adapter.min.js"></script><script src="webrtcstreamer.js"></script>
</head>
<body>
<script>
var webRtcServer;
window.onload = function() {webRtcServer = new WebRtcStreamer(document.getElementById("video"), location.protocol+"//" + location.hostname + ":8000");webRtcServer.connect("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov");
}
window.onbeforeunload = function() {if (webRtcServer !== null) {webRtcServer.disconnect();}
}
</script>
<video id="video" controls autoplay muted></video>
</body>
</html>
代碼解析
  • 引入了 adapter.min.jswebrtcstreamer.js 兩個必要的 JavaScript 庫。
  • 創建一個 WebRtcStreamer 實例,指定本地服務器地址及目標 RTSP 視頻流地址。
  • 頁面加載時自動連接至 RTSP 流,播放視頻。
  • 頁面卸載時,斷開連接,釋放資源。
應用案例與最佳實踐

示例 1:直播演示

  • 使用 WebRTC-Streamer 可以通過簡化的 Web 組件方式輕松展示來自 RTSP 源的實時視頻流。
<webrtc-streamer url="rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov">

示例 2:地圖上的直播流

  • 配合 Google Map APIWebRTC-Streamer 可以在地圖上顯示多個實時視頻流,適用于 監控交通管理 等領域。
其它生態項目

WebRTC-Streamer 還支持一系列相關生態項目,以擴展其功能和適用范圍:

  • webrtc-streamer-card:為 Home Assistant 提供的卡片插件,允許從 WebRTC-Streamer 服務中拉取零延遲視頻流,適用于智能家居。
  • rpi-webrtc-streamer:面向 樹莓派 系列微控制器的 WebRTC 流媒體軟件包,支持在邊緣設備上實現高效的音視頻處理。
  • Live555 Integration:通過整合 Live555 Media Server,增強 WebRTC-Streamer 在處理非標準音視頻格式方面的能力,擴展其應用場景。

附錄:WebRTC-Streamer項目地址

https://gitcode.com/gh_mirrors/we/webrtc-streamer/?utm_source=artical_gitcode&index=bottom&type=card&webUrl&isLogin=1

附錄:webrtcstreamer.js源碼

// webrtcstreamer.js
var WebRtcStreamer = (function() {/** * Interface with WebRTC-streamer API* @constructor* @param {string} videoElement - id of the video element tag* @param {string} srvurl -  url of webrtc-streamer (default is current location)*/var WebRtcStreamer = function WebRtcStreamer (videoElement, srvurl) {if (typeof videoElement === "string") {this.videoElement = document.getElementById(videoElement);} else {this.videoElement = videoElement;}this.srvurl           = srvurl || location.protocol+"//"+window.location.hostname+":"+window.location.port;this.pc               = null;    this.mediaConstraints = { offerToReceiveAudio: true, offerToReceiveVideo: true };this.iceServers = null;this.earlyCandidates = [];}WebRtcStreamer.prototype._handleHttpErrors = function (response) {if (!response.ok) {throw Error(response.statusText);}return response;}/** * Connect a WebRTC Stream to videoElement * @param {string} videourl - id of WebRTC video stream* @param {string} audiourl - id of WebRTC audio stream* @param {string} options -  options of WebRTC call* @param {string} stream  -  local stream to send*/WebRtcStreamer.prototype.connect = function(videourl, audiourl, options, localstream) {this.disconnect();// getIceServers is not already receivedif (!this.iceServers) {console.log("Get IceServers");fetch(this.srvurl + "/api/getIceServers").then(this._handleHttpErrors).then( (response) => (response.json()) ).then( (response) =>  this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream)).catch( (error) => this.onError("getIceServers " + error ))} else {this.onReceiveGetIceServers(this.iceServers, videourl, audiourl, options, localstream);}}/** * Disconnect a WebRTC Stream and clear videoElement source*/WebRtcStreamer.prototype.disconnect = function() {		if (this.videoElement?.srcObject) {this.videoElement.srcObject.getTracks().forEach(track => {track.stop()this.videoElement.srcObject.removeTrack(track);});}if (this.pc) {fetch(this.srvurl + "/api/hangup?peerid=" + this.pc.peerid).then(this._handleHttpErrors).catch( (error) => this.onError("hangup " + error ))try {this.pc.close();}catch (e) {console.log ("Failure close peer connection:" + e);}this.pc = null;}}    /** GetIceServers callback*/WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl, audiourl, options, stream) {this.iceServers       = iceServers;this.pcConfig         = iceServers || {"iceServers": [] };try {            this.createPeerConnection();var callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl);if (audiourl) {callurl += "&audiourl="+encodeURIComponent(audiourl);}if (options) {callurl += "&options="+encodeURIComponent(options);}if (stream) {this.pc.addStream(stream);}// clear early candidatesthis.earlyCandidates.length = 0;// create Offerthis.pc.createOffer(this.mediaConstraints).then((sessionDescription) => {console.log("Create offer:" + JSON.stringify(sessionDescription));this.pc.setLocalDescription(sessionDescription).then(() => {fetch(callurl, { method: "POST", body: JSON.stringify(sessionDescription) }).then(this._handleHttpErrors).then( (response) => (response.json()) ).catch( (error) => this.onError("call " + error )).then( (response) =>  this.onReceiveCall(response) ).catch( (error) => this.onError("call " + error ))}, (error) => {console.log ("setLocalDescription error:" + JSON.stringify(error)); });}, (error) => { alert("Create offer error:" + JSON.stringify(error));});} catch (e) {this.disconnect();alert("connect error: " + e);}	    }WebRtcStreamer.prototype.getIceCandidate = function() {fetch(this.srvurl + "/api/getIceCandidate?peerid=" + this.pc.peerid).then(this._handleHttpErrors).then( (response) => (response.json()) ).then( (response) =>  this.onReceiveCandidate(response)).catch( (error) => this.onError("getIceCandidate " + error ))}/** create RTCPeerConnection */WebRtcStreamer.prototype.createPeerConnection = function() {console.log("createPeerConnection  config: " + JSON.stringify(this.pcConfig));this.pc = new RTCPeerConnection(this.pcConfig);var pc = this.pc;pc.peerid = Math.random();		pc.onicecandidate = (evt) => this.onIceCandidate(evt);pc.onaddstream    = (evt) => this.onAddStream(evt);pc.oniceconnectionstatechange = (evt) => {  console.log("oniceconnectionstatechange  state: " + pc.iceConnectionState);if (this.videoElement) {if (pc.iceConnectionState === "connected") {this.videoElement.style.opacity = "1.0";}			else if (pc.iceConnectionState === "disconnected") {this.videoElement.style.opacity = "0.25";}			else if ( (pc.iceConnectionState === "failed") || (pc.iceConnectionState === "closed") )  {this.videoElement.style.opacity = "0.5";} else if (pc.iceConnectionState === "new") {this.getIceCandidate();}}}pc.ondatachannel = function(evt) {  console.log("remote datachannel created:"+JSON.stringify(evt));evt.channel.onopen = function () {console.log("remote datachannel open");this.send("remote channel openned");}evt.channel.onmessage = function (event) {console.log("remote datachannel recv:"+JSON.stringify(event.data));}}pc.onicegatheringstatechange = function() {if (pc.iceGatheringState === "complete") {const recvs = pc.getReceivers();recvs.forEach((recv) => {if (recv.track && recv.track.kind === "video") {console.log("codecs:" + JSON.stringify(recv.getParameters().codecs))}});}}try {var dataChannel = pc.createDataChannel("ClientDataChannel");dataChannel.onopen = function() {console.log("local datachannel open");this.send("local channel openned");}dataChannel.onmessage = function(evt) {console.log("local datachannel recv:"+JSON.stringify(evt.data));}} catch (e) {console.log("Cannor create datachannel error: " + e);}	console.log("Created RTCPeerConnnection with config: " + JSON.stringify(this.pcConfig) );return pc;}/** RTCPeerConnection IceCandidate callback*/WebRtcStreamer.prototype.onIceCandidate = function (event) {if (event.candidate) {if (this.pc.currentRemoteDescription)  {this.addIceCandidate(this.pc.peerid, event.candidate);					} else {this.earlyCandidates.push(event.candidate);}} else {console.log("End of candidates.");}}WebRtcStreamer.prototype.addIceCandidate = function(peerid, candidate) {fetch(this.srvurl + "/api/addIceCandidate?peerid="+peerid, { method: "POST", body: JSON.stringify(candidate) }).then(this._handleHttpErrors).then( (response) => (response.json()) ).then( (response) =>  {console.log("addIceCandidate ok:" + response)}).catch( (error) => this.onError("addIceCandidate " + error ))}/** RTCPeerConnection AddTrack callback*/WebRtcStreamer.prototype.onAddStream = function(event) {console.log("Remote track added:" +  JSON.stringify(event));this.videoElement.srcObject = event.stream;var promise = this.videoElement.play();if (promise !== undefined) {promise.catch((error) => {console.warn("error:"+error);this.videoElement.setAttribute("controls", true);});}}/** AJAX /call callback*/WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {console.log("offer: " + JSON.stringify(dataJson));var descr = new RTCSessionDescription(dataJson);this.pc.setRemoteDescription(descr).then(() =>  { console.log ("setRemoteDescription ok");while (this.earlyCandidates.length) {var candidate = this.earlyCandidates.shift();this.addIceCandidate(this.pc.peerid, candidate);				}this.getIceCandidate()}, (error) => { console.log ("setRemoteDescription error:" + JSON.stringify(error)); });}	/** AJAX /getIceCandidate callback*/WebRtcStreamer.prototype.onReceiveCandidate = function(dataJson) {console.log("candidate: " + JSON.stringify(dataJson));if (dataJson) {for (var i=0; i<dataJson.length; i++) {var candidate = new RTCIceCandidate(dataJson[i]);console.log("Adding ICE candidate :" + JSON.stringify(candidate) );this.pc.addIceCandidate(candidate).then( () =>      { console.log ("addIceCandidate OK"); }, (error) => { console.log ("addIceCandidate error:" + JSON.stringify(error)); } );}this.pc.addIceCandidate();}}/** AJAX callback for Error*/WebRtcStreamer.prototype.onError = function(status) {console.log("onError:" + status);}return WebRtcStreamer;})();if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {window.WebRtcStreamer = WebRtcStreamer;}if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {module.exports = WebRtcStreamer;}

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

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

相關文章

沃德校園助手系統php+uniapp

一款基于FastAdminThinkPHPUniapp開發的為校園團隊提供全套的技術系統及運營的方案&#xff08;目前僅適配微信小程序&#xff09;&#xff0c;可以更好的幫助你打造自己的線上助手平臺。成本低&#xff0c;見效快。各種場景都可以自主選擇服務。 更新日志 V1.2.1小程序需要更…

Linux 系統上以 root 用戶身份運行 ./mysql.server start 命令,但仍然收到 “Permission denied” 錯誤

如圖 1 所示&#xff0c;當在 Linux 系統上以 root 用戶身份運行 ./mysql.server start 命令&#xff0c;但仍然收到 “Permission denied” 錯誤時&#xff0c;這通常不是由于權限不足&#xff08;因為您已經是 root 用戶&#xff09;&#xff0c;而可能是由于 mysql.server 腳…

Android的Activity生命周期知識點總結,詳情

一. Activity生命周期 1.1 返回棧知識點 二. Activity狀態 2.1 啟動狀態 2.2 運行狀態 2.3 暫停狀態 2.4 停止狀態 2.5 銷毀狀態 三. Activity生存期 3.1 回調方法 3.2 生存期 四. 體驗Activity的生命周期 五. Activity被回收辦法 引言&#xff1a; 掌握Acti…

Python----PyQt開發(PyQt基礎,環境搭建,Pycharm中PyQttools工具配置,第一個PyQt程序)

一、QT與PyQT的概念和特點 1.1、QT QT是一個1991年由The Qt Company開發的跨平臺C圖形用戶界面應用程序開發 框架&#xff0c;可構建高性能的桌面、移動及Web應用程序。也可用于開發非GUI程序&#xff0c;比如 控制臺工具和服務器。Qt是面向對象的框架&#xff0c;使用特殊的代…

win10 系統 自定義Ollama安裝路徑 及模型下載位置

win10 系統 自定義Ollama安裝路徑 及模型下載位置 由于Ollama的exe安裝軟件雙擊安裝的時候默認是在C盤&#xff0c;以及后續的模型數據下載也在C盤&#xff0c;導致會占用C盤空間&#xff0c;所以這里單獨寫了一個自定義安裝Ollama安裝目錄的教程。 Ollama官網地址&#xff1…

微軟官方出品GPT大模型編排工具:7個開源項目

今天一起盤點下&#xff0c;12月份推薦的7個.Net開源項目&#xff08;點擊標題查看詳情&#xff09;。 1、一個瀏覽器自動化操作的.Net開源庫 這是一個基于 Google 開源的 Node.js 庫 Puppeteer 的 .NET 開源庫&#xff0c;方便開發人員使用無頭 Web 瀏覽器抓取 Web、檢索 Ja…

蘋果CMS站群插件的自動生成功能:提升網站流量的秘訣

引言 在數字營銷的浪潮中&#xff0c;站群技術因其強大的流量引導能力而備受青睞。蘋果CMS作為一款優秀的內容管理系統&#xff0c;憑借其靈活性和可擴展性&#xff0c;成為了站群管理的理想選擇。本文將詳細介紹蘋果CMS站群插件的自動生成功能&#xff0c;探討如何通過這一功…

VS Code User和System版區別【推薦使用System版本】and VSCode+Keil協同開發之Keil Assistant

VS Code User和System版區別 Chapter1 VS Code User和System版區別1. 對于安裝而言2. 結束語 Chapter2 VS Code 安裝、配置教程及插件推薦插件&#xff1a; Chapter3 VSCodeKeil協同開發之Keil Assistant1. 效果展示2. Keil Assistant簡介3. Keil Assistant功能特性4. 部署步驟…

大語言模型入門

大語言模型入門 1 大語言模型步驟1.1 pre-training 預訓練1.1.1 從網上爬數據1.1.2 tokenization1.1.2.1 tokenization using byte pair encoding 1.3 預訓練1.3.1 context1.3.2 training1.3.3 輸出 1.2 post-training1&#xff1a;SFT監督微調1.2.1 token 1.3 強化學習1.3.1 基…

DeepSeek R1 本地部署和知識庫搭建

一、本地部署 DeepSeek-R1&#xff0c;是幻方量化旗下AI公司深度求索&#xff08;DeepSeek&#xff09;研發的推理模型 。DeepSeek-R1采用強化學習進行后訓練&#xff0c;旨在提升推理能力&#xff0c;尤其擅長數學、代碼和自然語言推理等復雜任務 。 使用DeepSeek R1, 可以大大…

基于大數據的全國熱門旅游景點數據分析系統的設計與實現

【大數據】基于大數據的全國熱門旅游景點數據分析系統的設計與實現&#xff08;完整系統源碼開發筆記詳細部署教程&#xff09;? 目錄 一、項目簡介二、項目界面展示三、項目視頻展示 一、項目簡介 該系統主要包括登錄注冊、系統首頁、圖表分析、數據管理和個人信息五大功能模…

李宏毅機器學習筆記:【6.Optimization、Adaptive Learning Rate】

Optimization 1.Adaptive Learning Rate2.不同的參數需要不同的學習率3.Root Mean Square4.RMSProp5.Adam6.learning rate scheduling7.warm up總結 critical point不一定是你在訓練一個network時候遇到的最大的障礙。 1.Adaptive Learning Rate 也就是我們要給每個參數不同的…

Task03:Ollama API 的使用

Ollama API 使用指南 簡介 Ollama 提供了強大的 REST API&#xff0c;使開發者能夠方便地與大語言模型進行交互。通過 Ollama API&#xff0c;用戶可以發送請求并接收模型生成的響應&#xff0c;應用于自然語言處理、文本生成等任務。本文將詳細介紹生成補全、對話生成的基本…

我用AI做數據分析之四種堆疊聚合模型的比較

我用AI做數據分析之四種堆疊聚合模型的比較 這里AI數據分析不僅僅是指AI生成代碼的能力&#xff0c;我想是測試AI數據分析方面的四個能力&#xff0c;理解人類指令的能力、撰寫代碼的能力、執行代碼的能力和解釋結果的能力。如果這四個能力都達到了相當的水準&#xff0c;才可…

DC-6靶機滲透測試全過程

目錄 前期準備 一、滲透測試 1.IP地址查詢 2.端口信息搜尋 3.網頁信息搜集 wappalyzer WPScan 反彈shell graham用戶 反彈出jens的shell nmap提權 二、總結 前期準備 攻擊機&#xff1a; kali windows11 靶機&#xff1a;DC-6靶機&#xff08;調至NAT模式&#xff0…

[操作系統] 基礎IO:系統文件I/O

在 Linux 操作系統中&#xff0c;文件 I/O&#xff08;輸入/輸出&#xff09;是程序與文件系統交互的基礎。理解文件 I/O 的工作原理對于編寫高效、可靠的程序至關重要。本文將深入探討系統文件 I/O 的機制。 一種傳遞標志位的方法 在 Linux 中&#xff0c;文件的打開操作通常…

3.8 AI驅動的市場調研革命:從數據采集到競品策略生成的閉環實踐指南

AI驅動的市場調研革命:從數據采集到競品策略生成的閉環實踐指南 引言:智能時代的高效市場洞察 Forrester研究顯示,使用AI輔助市場調研可使數據采集效率提升8倍,策略生成速度加快4倍。本文以GitHub Sentinel、LanguageMentor為案例,揭示如何構建AI增強型市場分析體系,實現…

AF3 MmcifObject類解讀

AlphaFold3 中 MmcifObject類 是 解析 mmCIF 文件的核心數據結構,用于存儲解析后的蛋白質結構信息,包含PDB 頭部信息、Biopython 解析的結構、鏈序列信息等。 下面代碼包含 Monomer 、AtomSite、ResiduePosition、ResidueAtPosition、 MmcifObject以及ParsingResult數據類的…

網絡安全 “免疫力”:從人體免疫系統看防御策略

在當今數字化時代&#xff0c;網絡安全已變得至關重要。每天&#xff0c;我們的網絡系統都面臨著來自各方的威脅&#xff0c;就像人體時刻暴露在各種病原體中一樣。今天&#xff0c;我們就來聊聊網絡安全與人體免疫系統的奇妙聯系&#xff0c;看看從免疫系統中能汲取哪些構建強…

滾動彈幕案例

滾動彈幕案例 一、需求 1.頁面上漂浮字體大小不一、顏色不一&#xff0c;從左向右滾動的彈幕&#xff1b; 2.底部中間有一個發送功能&#xff0c;可以發送新的彈幕&#xff1b; 3.底部的發送部分可以向下收起和彈出。 二、html <div class"container"><…