国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

webrtc 入門第三章 建立連接

這篇具有很好參考價(jià)值的文章主要介紹了webrtc 入門第三章 建立連接。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

webrtc 入門第三章 建立連接

一、介紹
1、概述

? 在前面的章節(jié)我們學(xué)習(xí)了通過webrtc的基本操作實(shí)現(xiàn)了獲取本地媒體流、音視頻的獲取與操作。在得到本地的媒體流后我們就需要將本地媒體數(shù)據(jù)發(fā)送到遠(yuǎn)端,遠(yuǎn)端街道媒體流后渲染可視化,從而達(dá)到通話的目的。

? RTCPeerConnection 連接的核心pai接口,使用它可以將本地流發(fā)送到遠(yuǎn)端,同時(shí)也可以將遠(yuǎn)端媒體流發(fā)送到本地從而實(shí)現(xiàn)連接。在使用過程中需要用到信令服務(wù)器中轉(zhuǎn)信息和STUN服務(wù)器打樁服務(wù)。

二、實(shí)踐
1、RTCPeerConnection 連接對(duì)象

1.RTCPeerConnection 后文簡(jiǎn)稱pc連接對(duì)象。本地為L(zhǎng)ocal對(duì)象,遠(yuǎn)端為Remote對(duì)象,在一對(duì)一音視頻通話場(chǎng)景中pc對(duì)象總是成對(duì)出現(xiàn)。

方法名 參數(shù) 說明
RTCPeerConnection RTCConfiguration連接配置參數(shù) RTCPeerConnection接口代表一個(gè)本地到遠(yuǎn)端的webrtc連接,這個(gè)連接提供了創(chuàng)建,保持,監(jiān)控,關(guān)閉連接的方法實(shí)現(xiàn),在創(chuàng)建時(shí)需要向其傳入配置參數(shù),及ICE配置信息
pc.createOffer RTCOfferOptions對(duì)象 創(chuàng)建提議Offer方法,此方法會(huì)返回SDP offer信息,即RTCSessionDescription對(duì)象
pc.setLocalDescription RTCSessionDescription 對(duì)象 設(shè)置本地SDP描述信息
pc.setRemoteDescription RTCSessionDescription 對(duì)象 設(shè)置遠(yuǎn)端SDP描述信息,接收到遠(yuǎn)端發(fā)來的SDP信息后使用本方法
pc.createAnswer RTCAnswerOptions 對(duì)象,可選 創(chuàng)建應(yīng)答Answer方法,此方法會(huì)返回SDPAnswer信息,即RTCSessionDescription 對(duì)象
RTCPIceCandidate wevrtc網(wǎng)絡(luò)信息,端口,ip等。
pc.addIceCandidate RTCPIceCandidate對(duì)象 pc連接添加對(duì)方法的IceCandidate對(duì)象,得到對(duì)放的網(wǎng)絡(luò)地址等
2.流程圖

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-u3UNWW3f-1646320648144)(C:\Users\Administrator\Desktop\liucheng.png)]

3、連接流程

WebRTC連接流程比較復(fù)雜,學(xué)習(xí)過程只考慮將本地Peer-A的流發(fā)送到遠(yuǎn)端Peer-B,具體流程如下(A-本地,B-遠(yuǎn)端)

1.A獲取到本地媒體流 MediaStram:通過getUserMedia 方法獲取到本地的音視頻流數(shù)據(jù)

2.A生成本地連接對(duì)象PC-A:創(chuàng)建一個(gè)RTCPeerConnection接口,該接口提供創(chuàng)建、保持、關(guān)閉等方法,在設(shè)置前需要設(shè)置ICE服務(wù)器地址

varconfiguration={"iceServers": [{"url": "stun:stun.1.google.com:19302"}]},
that.peerConnA = new RTCPeerConnection(that.configuration)

3.A將本地視頻流加入PC-A :

that.localStream.getTracks().forEach((track) => {
    that.peerConnA.addTrack(track, that.localStream)
})

4.A創(chuàng)建提議Offer: that.peerConnA.createOffer() 返回一個(gè)RTCPSessionDescription對(duì)象,主要是SDP信息是會(huì)話的描述信息,兩個(gè)端連接過程中通過他來進(jìn)行互相的信息交換,達(dá)到媒體協(xié)商。

5.A-設(shè)置本地描述:創(chuàng)建offer成功后設(shè)置本地的描述信息 that.peerConnA.setLocalDescription(event)

6.A將Offer發(fā)送給B:通常需要一個(gè)信令服務(wù)器例如websocket 來轉(zhuǎn)發(fā)offer數(shù)據(jù)

7.B生成PC-B對(duì)象:同A端一樣,B端也要生成一個(gè)RCTPeerConnection對(duì)象來應(yīng)答A端發(fā)送的Answer,媒體流等

8.B端設(shè)置遠(yuǎn)端描述:當(dāng)B端接收到來自A端的offer信息后使用setRemoteDescription() 方法設(shè)置來自遠(yuǎn)端A的描述信息

9.B端生成應(yīng)答Answer信息:B端使用pc.ceateAnswer()方法生成一個(gè)應(yīng)答A端RTCPSessionDescription對(duì)象,主要包括SDP信息,應(yīng)答Answer和提議Offer是成對(duì)出現(xiàn)的。

10.B端設(shè)置本地描述:B端創(chuàng)建Answer后設(shè)置本地的描述信息 that.peerConnB.setLocalDescription(event)

11.B端返回Answer給A端:通過信令服務(wù)器將Answer發(fā)送給A端

12.A端設(shè)置來自B端的Answer描述信息:當(dāng)A端通過websocket信令服務(wù)獲得到的Answer信息后,調(diào)用that.peerConnA.setRemoteDescription()方法設(shè)置遠(yuǎn)端的描述

13.交換ICE候選地址信息:建立連接時(shí),會(huì)回調(diào)onicecandidate事件,傳遞ice候選地址,同樣也需要websocket信令服務(wù)來做消息轉(zhuǎn)發(fā),對(duì)方接受到以后調(diào)用addIceCandidate()方法設(shè)置接收到的候選地址

14.交換與使用媒體流:當(dāng)一方執(zhí)行addTrack后,另一方的RTCPerrConnection會(huì)觸發(fā)track事件回調(diào),在回調(diào)事件中可以獲得對(duì)方的軌道里的媒體流,這樣就能播放對(duì)方的流媒體。

that.peerConnB.addEventListener("track", that.getRemoteStream)
getRemoteStream: function (event) {
  let that = this
      if (that.remoteVideo.srcObject !== event.streams[0]) {
             that.remoteVideo.srcObject = event.streams[0]
             this.remoteVideo.play();
             console.log("開始獲取遠(yuǎn)端視頻流")
      }
}
4、示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>RTCPeerConnection 連接測(cè)試</title>
</head>
<body>
<div class="app">
    <input type="button" title="開始" value="開始" v-on:click="start"/>
    <input type="button" title="呼叫" value="呼叫" v-on:click="call"/>
    <input type="button" title="掛斷" value="掛斷" v-on:click="stop"/>
    <input type="button" value="同步" v-on:click="canPlay"/>
    <hr>

    <span>當(dāng)前使用視頻設(shè)備:{[videoDeviceName]}</span>
    <br> <br>
    <span>當(dāng)前使用音頻設(shè)備:{[audioDeviceName]}</span>
    <hr>

    {{/*    本地視頻*/}}
    <video id="localVideo" class="localVideo" height="240px" width="280px" playsinline autoplay muted></video>
    {{/*    遠(yuǎn)端視頻*/}}
    <video id="remoteVideo" class="remoteVideo" height="240px" width="280px" playsinline autoplay muted></video>
    {{/*    本地mp4文件*/}}

    <br> <br>
    <hr>
    <span>測(cè)試本地mp4文件</span>

    <br>

    <br>
    <video id="myVideo" class="myVideo" autoplay="autoplay" width="400" height="200" controls loop muted
           v-on:oncanplay="canPlay">
        <source src="/static/file/capture.mp4" type="video/mp4">
    </video>

</div>
</body>
<script src="/static/js/Vue.2.5.3.js"></script>
<script type="text/javascript">
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
    let vm = new Vue({
        el: ".app",
        delimiters: ['{[', ']}'],
        data: {
            // 測(cè)試我的視頻
            myVideo: null,
            // 本地視頻
            localVideo: null,
            // 本地視頻流
            localStream: null,
            // 遠(yuǎn)端視頻流
            remoteVideo: null,
            isOpen: false,
            videoDeviceName: "",
            audioDeviceName: "",
            // ICE service地址
            configuration: {
                "iceServers": [{"url": "stun:stun.1.google.com:19302"}]
            },
            // peerConnA 本地對(duì)象
            peerConnA: null,
            // peerConnB 遠(yuǎn)程對(duì)象
            peerConnB: null,
            // 本地視頻軌道
            videoTracks: [],
            // 本地音頻軌道
            audioTrack: []
        },
        methods: {
            canPlay: function () {
                alert("zheli")
                let fps = 0;
                // 捕捉
                if (this.myVideo.captureStream) {
                    this.localStream = this.myVideo.captureStream(fps)
                } else if (this.capture.mozCaptureStream) {
                    this.localStream = this.myVideo.mozCaptureStream(fps)
                } else {
                    alert("不支持 captureStream")
                }

            },
            stop: function () {
                let that = this
                that.peerConnB.close()
                that.peerConnA.close()
                that.peerConnA = null
                that.peerConnB = null
                console.log("關(guān)閉會(huì)話")
            }
            ,
            start: async function () {
                let that = this;
                if (that.isOpen) {
                    return
                }
                try {
                    that.localStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true})
                    that.isOpen = true
                    that.localVideo.srcObject = that.localStream
                    that.remoteVideo.srcObject = that.localStream
                    console.log("獲取本地流成功", that.localStream)
                    // 獲取設(shè)備軌道
                    that.videoTracks = that.localStream.getVideoTracks()
                    that.audioTrack = that.localStream.getAudioTracks()
                    if (that.videoTracks.length > 0) {
                        that.videoDeviceName = that.videoTracks[0].label
                    }
                    if (that.audioTrack.length > 0) {
                        that.audioDeviceName = that.audioTrack[0].label
                    }

                } catch (e) {
                    console.log("getUserMedia 錯(cuò)誤" + e)
                }
            }
            ,
            call: async function () {
                let that = this;
                console.log("開始呼叫")

                //  監(jiān)聽返回icecandidate 信息
                that.peerConnA = new RTCPeerConnection(that.configuration)
                that.peerConnA.addEventListener("icecandidate", that.onIceCandidateA)
                that.peerConnB = new RTCPeerConnection(that.configuration)
                that.peerConnB.addEventListener("icecandidate", that.onIceCandidateB)
                // 監(jiān)聽I(yíng)CE狀態(tài)變化
                that.peerConnA.addEventListener("iceconnectionstatechange", that.onIceStateChangeA)
                that.peerConnB.addEventListener("iceconnectionstatechange", that.onIceStateChangeB)

                // 監(jiān)聽track,獲取遠(yuǎn)端視頻流視頻
                that.peerConnB.addEventListener("track", that.getRemoteStream)
                // 將本地流加入本地連接
                that.localStream.getTracks().forEach((track) => {
                    that.peerConnA.addTrack(track, that.localStream)
                })


                // 創(chuàng)建通話offer
                try {
                    console.log("peerConnA 創(chuàng)建offer會(huì)話開始")
                    const offer = await that.peerConnA.createOffer()
                    await that.onCreateOfferSuccess(offer)
                } catch (e) {
                    console.log("創(chuàng)建會(huì)話描述SD失?。?, e.toString())
                }
            }
            ,

            // 創(chuàng)建提議offer成功
            onCreateOfferSuccess: async function (event) {
                let that = this
                // 設(shè)置連接描述
                console.log("peerConnA 創(chuàng)建offer返回得SDP信息", event.sdp)
                console.log("設(shè)置peerConnA得本地描述start...")
                try {
                    await that.peerConnA.setLocalDescription(event)
                    console.log("設(shè)置peerConnA得本地描述成功")
                } catch (e) {
                    console.log("設(shè)置peerConnA得本地描述錯(cuò)誤:", e.toString())
                }

                console.log("設(shè)置peerConnB得遠(yuǎn)端描述 start")
                try {
                    await that.peerConnB.setRemoteDescription(event)
                    console.log("設(shè)置peerConnB得遠(yuǎn)端描述成功")

                } catch (e) {
                    console.log("設(shè)置peerConnB得遠(yuǎn)端描述錯(cuò)誤:", e.toString())
                }

                // 開始應(yīng)答
                console.log("peerConnB創(chuàng)建應(yīng)答 answer start")
                try {
                    const answer = await that.peerConnB.createAnswer()
                    console.log("peerConnB創(chuàng)建應(yīng)答成功")
                    await that.onCreateAnswerSuccess(answer)
                } catch (e) {
                    console.log("peerConnB創(chuàng)建應(yīng)答錯(cuò)誤:", e.toString())
                }

            }
            ,

            // 創(chuàng)建answer應(yīng)答成功
            onCreateAnswerSuccess: async function (answer) {
                let that = this
                console.log("peerConnB創(chuàng)建應(yīng)答answer數(shù)據(jù):", answer)
                console.log("peerConnA與peerConnB交換應(yīng)答answer信息 start")

                try {
                    await that.peerConnB.setLocalDescription(answer)
                    console.log("設(shè)置peerConnB得本地answer 應(yīng)答遠(yuǎn)端描述成功")

                } catch (e) {
                    console.log("設(shè)置peerConnB得本地answer應(yīng)答描述錯(cuò)誤:", e.toString())
                }

                try {
                    await that.peerConnA.setRemoteDescription(answer)
                    console.log("設(shè)置peerConnA得遠(yuǎn)端answer應(yīng)答描述成功")

                } catch (e) {
                    console.log("設(shè)置peerConnA得遠(yuǎn)端answer應(yīng)答描述錯(cuò)誤:", e.toString())
                }
            }
            ,

            // 獲取遠(yuǎn)端視頻
            getRemoteStream: function (event) {
                let that = this
                console.log("獲取遠(yuǎn)端視頻數(shù)據(jù)如下:")
                console.log(event)
                if (that.remoteVideo.srcObject !== event.streams[0]) {
                    that.remoteVideo.srcObject = event.streams[0]
                    this.remoteVideo.play();
                    console.log("開始獲取遠(yuǎn)端視頻流")
                }
            }
            ,
            // 監(jiān)聽I(yíng)CE狀態(tài)變化事件回調(diào)方法
            onIceStateChangeA: function (event) {
                console.log("監(jiān)聽 peerConnA ICE狀態(tài)", this.peerConnA.iceConnectionState)
                console.log(event)
            }
            ,
            // 監(jiān)聽I(yíng)CE狀態(tài)變化事件回調(diào)方法
            onIceStateChangeB: async function (event) {
                console.log("監(jiān)聽 peerConnB ICE狀態(tài)", this.peerConnB.iceConnectionState)
                console.log(event)
            }
            ,

            onIceCandidateA: async function (event) {
                let that = this

                try {
                    if (event.candidate) {
                        // 直接交換candidate數(shù)據(jù),就不需要通過信令服務(wù)器傳送
                        await that.peerConnB.addIceCandidate(event.candidate)
                        console.log("peerConnB IceCandidate----------")
                        console.log(event)
                        that.onAddIceCandidateSuccess(that.peerConnB)
                    }
                } catch (e) {
                    that.onAddIceCandidateError(that.peerConnB, e)
                }
                console.log("onIceCandidateA data:" + event.candidate)
            }
            ,
            onIceCandidateB: async function (event) {
                let that = this
                try {
                    if (event.candidate) {
                        await that.peerConnA.addIceCandidate(event.candidate)
                        console.log("peerConnA IceCandidate----------")
                        console.log(event)
                        that.onAddIceCandidateSuccess(that.peerConnA)
                    }
                } catch (e) {
                    that.onAddIceCandidateError(that.peerConnA, e)
                }
                console.log("onIceCandidateB data:" + event.candidate)
            },
            //
            onAddIceCandidateSuccess: function (pc) {
                console.log("添加" + this.getPcName(pc) + "      IceCandidate 成功")
            },

            onAddIceCandidateError: function (pc, err) {
                console.log("添加" + this.getPcName(pc) + "       IceCandidate 失敗" + err.toString())
            },
            getPcName: function (pc) {
                return (pc === this.peerConnA) ? "peerConnA" : "peerConnB"
            },
        }
        ,
        mounted: function () {
            this.localVideo = document.getElementById('localVideo');
            this.remoteVideo = document.getElementById('remoteVideo');
            this.myVideo = document.getElementById('myVideo');
        }
    })
</script>
</html>

webrtc 入門第三章 建立連接

			本地								遠(yuǎn)端同步           

?

在上述程序中未使用信令服務(wù)器作交換ICE和SDP數(shù)據(jù),而是采用本地直接添加的方式,來實(shí)現(xiàn)了RTCPeerConnection的連接流程。

其連接過程也和第三段的流程一樣,先獲取本地的媒體地址,然后發(fā)起協(xié)商offer,設(shè)置本地描述,收到遠(yuǎn)端的協(xié)商offer后設(shè)置遠(yuǎn)端描述,生成會(huì)話offer,設(shè)置本地描述后發(fā)給提議方,提議方收到應(yīng)答會(huì)話offer后,設(shè)置遠(yuǎn)端描述,整個(gè)流程結(jié)束。

三、總結(jié)

本章介紹了webrtc的連接流程即api,在一對(duì)一的對(duì)接過程中可以直接使用,其連接過程比較復(fù)雜也相當(dāng)繁瑣。學(xué)者需要先了解其連接原理和流程,然后再去結(jié)合代碼即可掌握。另外學(xué)者們需要掌握一下幾點(diǎn)。

1.對(duì)于媒體流的操作轉(zhuǎn)換例如:獲取視頻的尺寸格式,監(jiān)聽遠(yuǎn)端視頻流的變化,音頻大小變化,視頻清晰度自適應(yīng),編碼方式。

2.了解提議(offer)/應(yīng)答(answer)里的信息:這些是SDP信息包含,如分辨率,格式,編碼等。

3.了解Candidate信息:這些也是SDP信息,里面包括媒體協(xié)商的信息,主要包括服務(wù)信息,如中繼,打樁,服務(wù)器的ip和端口

地址,然后發(fā)起協(xié)商offer,設(shè)置本地描述,收到遠(yuǎn)端的協(xié)商offer后設(shè)置遠(yuǎn)端描述,生成會(huì)話offer,設(shè)置本地描述后發(fā)給提議方,提議方收到應(yīng)答會(huì)話offer后,設(shè)置遠(yuǎn)端描述,整個(gè)流程結(jié)束。

三、總結(jié)

本章介紹了webrtc的連接流程即api,在一對(duì)一的對(duì)接過程中可以直接使用,其連接過程比較復(fù)雜也相當(dāng)繁瑣。學(xué)者需要先了解其連接原理和流程,然后再去結(jié)合代碼即可掌握。另外學(xué)者們需要掌握一下幾點(diǎn)。

1.對(duì)于媒體流的操作轉(zhuǎn)換例如:獲取視頻的尺寸格式,監(jiān)聽遠(yuǎn)端視頻流的變化,音頻大小變化,視頻清晰度自適應(yīng),編碼方式。

2.了解提議(offer)/應(yīng)答(answer)里的信息:這些是SDP信息包含,如分辨率,格式,編碼等。

3.了解Candidate信息:這些也是SDP信息,里面包括媒體協(xié)商的信息,主要包括服務(wù)信息,如中繼,打樁,服務(wù)器的ip和端口

4.通過學(xué)習(xí)視頻連接后,可以進(jìn)行舉一反三實(shí)現(xiàn)canvas繪畫板的同步功能。文章來源地址http://www.zghlxwxcb.cn/news/detail-409610.html

到了這里,關(guān)于webrtc 入門第三章 建立連接的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【UnityShader入門精要學(xué)習(xí)筆記】第三章(1)Unity Shader介紹

    【UnityShader入門精要學(xué)習(xí)筆記】第三章(1)Unity Shader介紹

    本系列為作者學(xué)習(xí)UnityShader入門精要而作的筆記,內(nèi)容將包括: 書本中句子照抄 + 個(gè)人批注 項(xiàng)目源碼 一堆新手會(huì)犯的錯(cuò)誤 潛在的太監(jiān)斷更,有始無終 總之適用于同樣開始學(xué)習(xí)Shader的同學(xué)們進(jìn)行有取舍的參考。 從本章節(jié)開始我們要學(xué)習(xí)Shader相關(guān)的知識(shí)了,諸位看客可能有的

    2024年02月02日
    瀏覽(25)
  • 《Jetpack Compose從入門到實(shí)戰(zhàn)》第三章 定制 UI 視圖

    《Jetpack Compose從入門到實(shí)戰(zhàn)》第三章 定制 UI 視圖

    -ui.theme.Color.kt ui.theme.Type.kt 先將Nunito Sans字體家族放入 res/font,再根據(jù)設(shè)計(jì)稿寫代碼 ui.theme/Shape.kt CompositionLocal 是 Jetpack Compose 中的一種數(shù)據(jù)傳遞方式。它可以在組合組件之間傳遞可變數(shù)據(jù),而無需通過 props 或 state 管理器來傳遞數(shù)據(jù)。這個(gè)特性比傳統(tǒng)的數(shù)據(jù)傳遞方式更為高效

    2024年02月07日
    瀏覽(19)
  • 【UnityShader入門精要學(xué)習(xí)筆記】第三章(2)Unity Shader的形式,章節(jié)答疑

    【UnityShader入門精要學(xué)習(xí)筆記】第三章(2)Unity Shader的形式,章節(jié)答疑

    本系列為作者學(xué)習(xí)UnityShader入門精要而作的筆記,內(nèi)容將包括: 書本中句子照抄 + 個(gè)人批注 項(xiàng)目源碼 一堆新手會(huì)犯的錯(cuò)誤 潛在的太監(jiān)斷更,有始無終 總之適用于同樣開始學(xué)習(xí)Shader的同學(xué)們進(jìn)行有取舍的參考。 (該系列筆記中大多數(shù)都會(huì)復(fù)習(xí)前文的知識(shí),特別是前文知識(shí)非

    2024年02月02日
    瀏覽(19)
  • 「第三章」python-docx 添加標(biāo)題,word標(biāo)題從入門到精通

    ?? 1. add_heading() 簡(jiǎn)介 ?? 2. add_heading() 基本用法 ?? 3. 設(shè)置不同級(jí)別的標(biāo)題 ?? 4. 設(shè)置帶有特殊字符的標(biāo)題 ?? 5. 使用循環(huán)添加多個(gè)標(biāo)題 ?? 6. 使用不同樣式添加標(biāo)題 ?? 7. 結(jié)合其他元素使用標(biāo)題 ?? 8. 為標(biāo)題設(shè)置復(fù)雜多變的樣式 最近一段時(shí)間,一直在更新python關(guān)于PDF文檔、

    2024年02月02日
    瀏覽(25)
  • maven從入門到精通 第三章 Maven中形成web對(duì)Java工程的依賴

    maven從入門到精通 第三章 Maven中形成web對(duì)Java工程的依賴

    從來只有war包中含有jar包,而沒有jar包中含有war包 web工程依賴的java工程,就是jar包,這個(gè)jar包經(jīng)過自動(dòng)化部署后,會(huì)放在web工程的web-inf/lib目錄下 在 pro02-maven-web 工程的 pom.xml 中,找到 dependencies 標(biāo)簽,在 dependencies 標(biāo)簽中做如下配置 證明在Web工程中可以使用Java工程中創(chuàng)建的

    2024年02月02日
    瀏覽(22)
  • 【第三章 Python 機(jī)器學(xué)習(xí)入門之Series和DataFrame的創(chuàng)建、索引、切片、數(shù)據(jù)清洗、數(shù)據(jù)分析等】

    【第三章 Python 機(jī)器學(xué)習(xí)入門之Series和DataFrame的創(chuàng)建、索引、切片、數(shù)據(jù)清洗、數(shù)據(jù)分析等】

    第一章 Python 機(jī)器學(xué)習(xí)入門之Pandas庫(kù)的使用 第二章 Python 機(jī)器學(xué)習(xí)入門之NumPy庫(kù)的使用 第四章 Python 機(jī)器學(xué)習(xí)入門之?dāng)?shù)據(jù)可視化 第五章 Python 機(jī)器學(xué)習(xí)入門之機(jī)器學(xué)習(xí)算法 第六章 Python 機(jī)器學(xué)習(xí)入門之實(shí)戰(zhàn)項(xiàng)目 Series是一種一維數(shù)組,可以通過以下方式創(chuàng)建: 通過列表創(chuàng)建Ser

    2024年02月05日
    瀏覽(96)
  • 第三章 decimal模塊

    第三章 decimal模塊

    decimal 模塊是 Python 提供的用于進(jìn)行十進(jìn)制定點(diǎn)和浮點(diǎn)運(yùn)算的內(nèi)置模塊。使用它可以快速正確地進(jìn)行十進(jìn)制定點(diǎn)和浮點(diǎn)數(shù)的舍入運(yùn)算,并且可以控制有效數(shù)字的個(gè)數(shù)。 使用 decimal 模塊主要是因?yàn)樗c Python 自帶的浮點(diǎn)數(shù)相比,有以下優(yōu)點(diǎn) : 基于浮點(diǎn)模型,提供與數(shù)字計(jì)算相同

    2024年02月09日
    瀏覽(16)
  • 第三章:函數(shù)

    1.定義 設(shè) x , y 是兩個(gè)變量,x的變化范圍是實(shí)數(shù)集D,如果對(duì)于任何的x∈D,按照一定的法則都有唯一確定的y值與之對(duì)應(yīng)。則稱變量y是變量x的函數(shù)。記為 y = f(x) 。稱D為函數(shù)的 定義域 ,x為自變量,y為因變量。全體函數(shù)值的集合稱為函數(shù)y的 值域 。 2.函數(shù)的表示方法 1. 公式

    2024年02月01日
    瀏覽(29)
  • 第三章 選擇與循環(huán)

    第三章 選擇與循環(huán)

    程序員必備技能(思想):增量編寫法。每寫一部分代碼要及時(shí)運(yùn)行看結(jié)果是否正確,對(duì)于復(fù)雜程序很重要。 常用的運(yùn)算符優(yōu)先級(jí): 邏輯非 ! 算術(shù)運(yùn)算符 關(guān)系運(yùn)算符 || 賦值運(yùn)算符 單目運(yùn)算符 邏輯非 ! 算術(shù)運(yùn)算符 +、-、×、/、% 關(guān)系運(yùn)算符 、、=、=、==、!= 邏輯運(yùn)算符 、|

    2024年02月09日
    瀏覽(32)
  • 第三章-上網(wǎng)行為安全

    第三章-上網(wǎng)行為安全

    1)寬帶濫用 2)上網(wǎng)難監(jiān)管 3)信息泄露 4)網(wǎng)絡(luò)違法 5)安全威脅 1)上網(wǎng)行為三要素:用戶、流量、行為 2)功能需求 (AC的功能)-- 重點(diǎn) 用戶認(rèn)證 應(yīng)用控制 網(wǎng)頁(yè)過濾 行為審計(jì) 流量管理 應(yīng)用選路 互聯(lián)網(wǎng)上網(wǎng)行為管控 一體化網(wǎng)關(guān) 無線Wi-Fi管控營(yíng)銷 無線防共享上網(wǎng) 全網(wǎng)上

    2024年01月23日
    瀏覽(32)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包