node.js中ws模塊創(chuàng)建服務(wù)端與客戶端實(shí)例代碼
一、WebSocket出現(xiàn)的原因
1、Http協(xié)議發(fā)布REST API 的不足:
每次請(qǐng)求響應(yīng)完成之后,服務(wù)器與客戶端之間的連接就斷開(kāi)了,如果客戶端想要繼續(xù)獲取服務(wù)器的消息,必須再次向服務(wù)器發(fā)起請(qǐng)
求。這顯然無(wú)法適應(yīng)對(duì)實(shí)時(shí)通信有高要求的場(chǎng)景。
2、改善http的不足:Web通信領(lǐng)域出現(xiàn)了一些其他的解決方案,如輪詢、長(zhǎng)輪詢、服務(wù)器推送事件、WebSocket
(1)輪詢:就是重復(fù)發(fā)送新的請(qǐng)求到服務(wù)器。如果服務(wù)器沒(méi)有新的數(shù)據(jù),就發(fā)送適當(dāng)?shù)闹甘静㈥P(guān)閉連接。然后客戶端等待一段時(shí)間
(比如間隔一秒),再發(fā)送另一個(gè)請(qǐng)求。這種實(shí)現(xiàn)方式相對(duì)比較簡(jiǎn)單,無(wú)須做過(guò)多的更改。但缺點(diǎn)是輪詢的間隔過(guò)長(zhǎng),會(huì)導(dǎo)致用戶不能及
時(shí)接收到更新的數(shù)據(jù);輪詢時(shí)間過(guò)短,會(huì)導(dǎo)致查詢請(qǐng)求過(guò)多,增加服務(wù)器端的負(fù)擔(dān)。
(2)長(zhǎng)輪詢:客戶端發(fā)送一個(gè)請(qǐng)求到服務(wù)器,如果服務(wù)器端沒(méi)有新的數(shù)據(jù),就保持這個(gè)連接直到有數(shù)據(jù)。一旦服務(wù)器端有了數(shù)據(jù)
(消息)給客戶端,它就使用這個(gè)連接發(fā)送數(shù)據(jù)給客戶端,接著連接關(guān)閉
(3)服務(wù)器推送事件:Server-Sent Events(SSE),SSE通常重用一個(gè)連接處理多個(gè)消息(事件)。SSE還定義了一個(gè)專門的媒體類
型,用于描述一個(gè)從服務(wù)端發(fā)送到客戶端的簡(jiǎn)單格式。
(4)WebSocket:提供了一個(gè)真正的全雙工連接。發(fā)起者是一個(gè)客戶端,發(fā)送一個(gè)帶特殊HTTP頭的請(qǐng)求到服務(wù)端,通知服務(wù)器。
該方案的優(yōu)點(diǎn)是屬于html5標(biāo)準(zhǔn),已經(jīng)被大多數(shù)瀏覽器支持,而且是真正的全雙工,性能比較好,其缺點(diǎn)是實(shí)現(xiàn)起來(lái)比較復(fù)雜,需要對(duì)ws協(xié)議專門處理。
二、Node使用ws創(chuàng)建WebSocket服務(wù)器
1、Node.js原生API沒(méi)有提供對(duì)WebSocket的支持,需要安裝第三方包才能使用WebSocket功能
2、ws模塊:是一個(gè)用于支持WebSocket客戶端和服務(wù)器的框架。它易于使用,功能強(qiáng)大,且不依賴于其他環(huán)境
3、安裝ws:npm install ws
4、創(chuàng)建WebSocket服務(wù)器:
//創(chuàng)建一個(gè)WebSocket服務(wù)器,在8080端口啟動(dòng) const WebSocket = require('ws') const server = new WebSocket.Server({port:8080})
5、WebSocket.Server(options[,callback])方法中options對(duì)象所支持的參數(shù)
(1)host:綁定服務(wù)器的主機(jī)名
(2)port:綁定服務(wù)器的端口號(hào)
(3)backlog:掛起連接隊(duì)列的最大長(zhǎng)度
(4)server:預(yù)先創(chuàng)建的node.js http/s服務(wù)器
(5)verifyClient:可用于驗(yàn)證傳入連接的函數(shù)
(6)handleProtocols:可用于處理WebSocket子協(xié)議的函數(shù)
(7)path:僅接受與此路徑匹配的連接
(8)noServer:不啟用服務(wù)器模式
(9)clientTracking:指定是否跟蹤客戶端
(10)perMessageDeflate:?jiǎn)⒂?禁用消息壓縮
(11)maxPayload:允許的最大消息大?。ㄒ宰止?jié)為單位)
三、監(jiān)聽(tīng)連接:ws通過(guò)connection事件來(lái)監(jiān)聽(tīng)連接
server.on('connection',function connection(ws,req){ const ip = req.socket.remoteAddress const port = req.socket.remotePort const clientName = ip + port ? console.log('%s is connected ',clientName) }) //只要有WebSocket連接到該服務(wù)器,就會(huì)觸發(fā)'connection'事件;req對(duì)象可以用來(lái)獲取客戶端的信息,如ip、端口號(hào) //獲取所有已連接的客戶端信息,則可以使用server.clients數(shù)據(jù)集
四、發(fā)送數(shù)據(jù):ws通過(guò)send()方法來(lái)發(fā)送數(shù)據(jù)
/* send(data [,options][,callback]) data:發(fā)送的數(shù)據(jù) options對(duì)象: (1)compress:指定數(shù)據(jù)是否需要壓縮。默認(rèn)為true (2)binary:指定數(shù)據(jù)是否通過(guò)二進(jìn)制傳送。默認(rèn)是自動(dòng)檢測(cè) (3)mask:指定是否應(yīng)遮罩?jǐn)?shù)據(jù)。 (4)fin:指定數(shù)據(jù)是否為消息的最后一個(gè)片段。默認(rèn)為true */ server.on('connection',function connection(ws,req){ const ip = req.socket.remoteAddress const port = req.socket.remotePort const clientName = ip + port ? console.log('%s is connected ',clientName) ? ws.send('Welcome ' + clientName) })
五、接收數(shù)據(jù):ws通過(guò)message事件來(lái)接收數(shù)據(jù)。當(dāng)客戶端有消息發(fā)送給服務(wù)器時(shí),服務(wù)器就能夠觸發(fā)該消息
server.on('connection',function connection(ws,req){ const ip = req.socket.remoteAddress const port = req.socket.remotePort const clientName = ip + port ? console.log('%s is connected ',clientName) ? ws.send('Welcome ' + clientName) ? ws.on('message',function incoming(message){ console.log('received: %s from %s',message,clientName) server.clients.forEach(function each(client){ if(client.readyState === WebSocket.OPEN){ client.send(clientName +" -> " + message) } }) }) })
六、準(zhǔn)備的狀態(tài):ws中WebSocket類具有以下4中準(zhǔn)備狀態(tài)
1、CONNCETION:值為0,表示連接還沒(méi)有打開(kāi)
2、OPEN:值為1,表示連接已經(jīng)打開(kāi),可以通信了
3、CLOSING:值為2,表示連接正在關(guān)閉
4、CLOSED:值為2,表示連接已經(jīng)關(guān)閉
server.clients.forEach(function each(client){ if(client.readyState === WebSocket.OPEN){ client.send(clientName +" -> " + message) } })
七、關(guān)閉WebSocket服務(wù)器:通過(guò)監(jiān)聽(tīng)close事件關(guān)閉服務(wù)器
server.on('close',function close(){ console.log('disconnected') })
案例
1、服務(wù)器端:server.js
const WebSocket = require('ws') ? const server = new WebSocket.Server({port:8080}) ? server.on('open',function open(){ console.log('connected') }) ? server.on('close',function close(){ console.log('disconnected') }) ? server.on('connection',function connection(ws,req){ const ip = req.socket.remoteAddress const port = req.socket.remotePort const clientName = ip + port ? console.log('%s is connected ',clientName) ? ws.send('Welcome ' + clientName) ? ws.on('message',function incoming(message){ console.log('received: %s from %s',message,clientName) server.clients.forEach(function each(client){ if(client.readyState === WebSocket.OPEN){ client.send(clientName +" -> " + message) } }) }) })
2、客戶端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> var socket if (!window.WebSocket) { window.WebSocket = window.MozWebSocket } if(window.WebSocket){ socket = new WebSocket("ws://localhost:8080/ws") socket.onmessage = function(event){ var ta = document.getElementById('responseTest') ta.value = ta.value + '\n' + event.data } socket.onopen = function(event) { var ta = document.getElementById('responseTest') ta.value = '連接開(kāi)啟!' } ? socket.onclose = function(event) { var ta = document.getElementById('responseTest') ta.value = '連接關(guān)閉!' } }else{ alert('你的瀏覽器不支持WebSocket') } ? function send(message){ if(!window.WebSocket){ return } if(socket.readyState === WebSocket.OPEN){ socket.send(message) }else{ alert('連接沒(méi)有開(kāi)啟') } } </script> <form onsubmit="return false"> <h3>WebSocket 聊天室:</h3> <textarea id="responseTest" style="width: 500px;height: 300px;"></textarea> <br> <input type="text" name="message" style="width: 300px;" value="Welcome to woniuxy.com"> <input type="button" value="發(fā)送消息" onclick="send(this.form.message.value)"> <input type="button" value="清空聊天記錄" onclick="javascript:document.getElementById('responseTest').value=''"> </form> </body> </html>
總結(jié)
到此這篇關(guān)于node.js中ws模塊創(chuàng)建服務(wù)端與客戶端的文章就介紹到這了,更多相關(guān)node.js創(chuàng)建服務(wù)端與客戶端內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用pm2部署多個(gè)node.js項(xiàng)目的配置教程
目前似乎最常見(jiàn)的線上部署nodejs項(xiàng)目的有forever,pm2這兩種,而下面這篇文章主要給大家介紹了關(guān)于利用pm2部署多個(gè)node.js項(xiàng)目的配置教程,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-10-10Windows下安裝Bun像Node或Deno的現(xiàn)代JS運(yùn)行時(shí)
這篇文章主要為大家介紹了一款像Node或Deno的現(xiàn)代JavaScript運(yùn)行時(shí)的bun在Windows下安裝過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07基于Node.js構(gòu)建一個(gè)靈活的CLI命令行工具
在軟件開(kāi)發(fā)中,命令行界面(CLI)工具是必不可少的助手,本文主要介紹了如何使用Node.js構(gòu)建一個(gè)靈活的CLI工具,涵蓋從基礎(chǔ)命令處理到復(fù)雜的交互式問(wèn)答和遠(yuǎn)程模板下載,需要的可以參考下2024-03-03node.js實(shí)現(xiàn)微信JS-API封裝接口的示例代碼
這篇文章主要介紹了node.js實(shí)現(xiàn)微信JS-API封裝接口的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09nodejs中使用archive壓縮文件的實(shí)現(xiàn)代碼
這篇文章主要介紹了nodejs中使用archive壓縮文件的實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11Node.js中代碼重復(fù)與不一致的問(wèn)題及解決方案
在 Node.js 開(kāi)發(fā)中,代碼重復(fù)和不一致是常見(jiàn)的問(wèn)題,尤其是在項(xiàng)目規(guī)模擴(kuò)大和團(tuán)隊(duì)協(xié)作時(shí),這些問(wèn)題不僅會(huì)增加維護(hù)成本,還可能導(dǎo)致邏輯錯(cuò)誤和性能問(wèn)題,本文將探討這些問(wèn)題的常見(jiàn)原因,并提供相應(yīng)的解決方案,需要的朋友可以參考下2025-03-03windows實(shí)現(xiàn)npm和cnpm安裝步驟
這篇文章主要介紹了windows實(shí)現(xiàn)npm和cnpm安裝步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10Nodejs?Sequelize手冊(cè)學(xué)習(xí)快速入門到應(yīng)用
這篇文章主要為大家介紹了Nodejs?Sequelize手冊(cè)學(xué)習(xí)快速入門到應(yīng)用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10使用ExcelJS快速處理Node.js爬蟲(chóng)數(shù)據(jù)
Excel.js是一個(gè)強(qiáng)大的JavaScript庫(kù),它提供了方法處理Excel文件,例如創(chuàng)建和編輯工作簿、讀取和寫(xiě)入數(shù)據(jù)、處理行和列、設(shè)置樣式、導(dǎo)入和導(dǎo)出數(shù)據(jù)等,本文介紹使用ExcelJS快速處理Node.js爬蟲(chóng)數(shù)據(jù)的方法,一起看看吧2024-01-01