Websocket和Socket.io的區(qū)別及應(yīng)用

一、Websocket

Websocket是HTML5新增的一種全雙工通信協(xié)議,客戶端和服務(wù)端基于TCP握手連接成功后,兩者之間就可以建立持久性的連接,實現(xiàn)雙向數(shù)據(jù)傳輸。
傳統(tǒng)HTTP和Websocket的異同
不同點

  1. HTTP是單向數(shù)據(jù)流,客戶端向服務(wù)端發(fā)送請求,服務(wù)端響應(yīng)并返回數(shù)據(jù);Websocket連接后可以實現(xiàn)客戶端和服務(wù)端雙向數(shù)據(jù)傳遞。
  2. 由于是新的協(xié)議,HTTP的url使用"http//"或"https//"開頭;Websocket的url使用"ws//"開頭。

相同點

  1. 都需要建立TCP連接
  2. 都是屬于七層協(xié)議中的應(yīng)用層協(xié)議

傳統(tǒng)通過HTTP請求模擬雙向數(shù)據(jù)傳遞的方式是http+Polling(輪詢)和http+Long Polling(長輪詢)。輪詢(Polling)就是客戶端定時發(fā)送get請求向服務(wù)端請求數(shù)據(jù),這種方式能滿足一定的需求,但是存在一些問題,如果服務(wù)端沒有新數(shù)據(jù),但是客戶端get請求到的數(shù)據(jù)都是舊數(shù)據(jù),這樣不僅浪費了帶寬資源,而且占用CPU內(nèi)存。

LongPolling(長輪詢)就是在Polling上的一些改進,即如果服務(wù)端沒有新數(shù)據(jù)返回給客戶端,服務(wù)端會把當前的這個get請求保持住(hold),當有新數(shù)據(jù)時則返回新數(shù)據(jù),如果超過一定時間服務(wù)端仍沒有新數(shù)據(jù),則服務(wù)端返回超時請求,客戶端接收到超時請求,然后在發(fā)送get請求,一直循環(huán)執(zhí)行。雖然一定程度解決了帶寬資源和CPU內(nèi)存浪費情況,但是當服務(wù)端數(shù)據(jù)更新很快,這和輪詢(Polling)沒有本質(zhì)上的區(qū)別,而且http數(shù)據(jù)包的頭部數(shù)據(jù)量往往很大(通常有400多個字節(jié)),但是真正被服務(wù)器需要的數(shù)據(jù)卻很少(有時只有10個字節(jié)左右),這樣的數(shù)據(jù)包在網(wǎng)絡(luò)上周期性的傳輸,難免對網(wǎng)絡(luò)帶寬是一種浪費。在高并發(fā)的情況下,這對服務(wù)器是一個很大的挑戰(zhàn)。綜合上面輪詢的種種問題,Websocket終于華麗的登上了舞臺。
Websocket,這里簡單說明一下的使用方式。

const ws = new WebSocket("ws//:xxx.xx", [protocol])

ws.onopen = () => {
    ws.send('hello')
    console.log('send')
}

ws.onmessage = (ev) =>{
    console.log(ev.data)
    ws.close()
}

ws.onclose = (ev) =>{
    console.log('close')
}

ws.onerror = (ev) =>{
    console.log('error')
}

Websocket實例化后,前端可以使用以上介紹的方法進行對應(yīng)的操作,這些方法使用比較簡單,這里就不多介紹,由于想完全搭建一個Websocket服務(wù)端比較麻煩,又耗費時間,接下來主要講解實際應(yīng)用中與Websocket相關(guān)的庫。

二、Socket.io

實際應(yīng)用中,如果需要Websocke進行雙向數(shù)據(jù)通信,Socket.io是一個非常好的選擇。其實github上面也有通過JS封裝好的Websocket庫,ws可用于client和基于node搭建的服務(wù)端使用,但是用起來相對繁瑣,star相對Socket.io較少,所以不推薦使用。

Socket.io不是Websocket,它只是將Websocket和輪詢 (Polling)機制以及其它的實時通信方式封裝成了通用的接口,并且在服務(wù)端實現(xiàn)了這些實時機制的相應(yīng)代碼。也就是說,Websocket僅僅是 Socket.io實現(xiàn)實時通信的一個子集。因此Websocket客戶端連接不上Socket.io服務(wù)端,當然Socket.io客戶端也連接不上Websocket服務(wù)端。

三、簡單聊天實例

servce.js(服務(wù)端)

'use strict'

let express = require('express')
let path = require('path')
let app = express()
let server = require('http').createServer(app)
let io = require('socket.io')(server)

app.use('/', (req, res, next) => {
    res.status(200).sendFile(path.resolve(__dirname, 'index.html'))
})

io.on('connection', client => {
    console.log(client.id, '=======================')
    client.on('channel', data =>{
        console.log(data)
        io.emit('broadcast', data)
        // client.emit('channel', data)
    })
    client.on('disconnect', () =>{
        console.log('close')
    })
})

server.listen(3000, () => {
    console.log("The service listening on 3000 port")
})

index.html(客戶端)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>app</title>
    <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.slim.js"></script>
</head>
<body>
    <input type="text" id="input">
    <button id="btn">send</button>
    <div id="content-wrap"></div>
</body>
    <script>
        window.onload = () => {
            let inputValue = null

            let socket = io('http://localhost:3000')
            socket.on('broadcast', data =>{
                let content = document.createElement('p')
                content.innerHTML = data
                document.querySelector('#content-wrap').appendChild(content)
            })
            
            let inputChangeHandle = (ev) => {
                inputValue = ev.target.value
            }
            let inputDom = document.querySelector("#input")
            inputDom.addEventListener('input', inputChangeHandle, false)

            let sendHandle = () => {                
                socket.emit('channel', inputValue)
            }
            let btnDom = document.querySelector("#btn")
            btnDom.addEventListener('click', sendHandle, false)
            

            window.onunload = () => {
                btnDom.removeEventListener('click', sendHandle, false)
                inputDom.removeEventListener('input', inputChangeHandle, false)
            }
        }
    </script>

</html>

新開幾個客戶端頁面,其中一個頁面輸入value,其他幾個頁面馬上收到value消息,簡單的聊天頁面就完成了,其中,客戶端index.html頁面不用服務(wù)端返回,自己隨便創(chuàng)建個index.html是一樣的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容