在Node.js下運(yùn)用MQTT協(xié)議實(shí)現(xiàn)即時(shí)通訊及離線推送的方法
前言
前些日子了解到mqtt這樣一個(gè)協(xié)議,可以在web上達(dá)到即時(shí)通訊的效果,但網(wǎng)上并不能很方便地找到一篇目前版本的在node下正確實(shí)現(xiàn)這個(gè)協(xié)議的博客。
自己搗鼓了一段時(shí)間,理解不深刻,但也算是基本能夠達(dá)到使用目的。
本文尚未對(duì)離線消息的接收順序進(jìn)行處理。
代碼
服務(wù)端: server.js
//服務(wù)端引入中間件mosca let mosca = require('mosca') let settings = { port: 5112 } let server = new mosca.Server(settings) server.on('ready', function(){ console.log('Mosca server is up and running at port 5112'); }) server.on('published', function(packet, client) { console.log('Published', packet.payload) }) server.on('clientDisconnected', function(client){ console.log('disconnected: ', client.id) })
推送端: pub.js
//客戶端引入mqtt let mqtt = require('mqtt'); let client = mqtt.connect('mqtt://localhost', { port: 5112, clientId: 'cli_pub', }) let num = 0; setInterval(function (){ client.publish('test', 'Hello mqtt ' + (++num), {qos:1}, () => console.log(num)); }, 1000)
訂閱端: sub.js
let mqtt = require('mqtt') let client = mqtt.connect('mqtt://localhost', { port: 5112, clientId: 'cli_sub', }) client.subscribe('test',{qos:1}) client.on('message', function (topic, message) { console.log('received message: ', message.toString()) })
server運(yùn)行后,先啟動(dòng)pub,再啟動(dòng)sub,即可在sub中接收到推送過(guò)來(lái)的消息序列
至此實(shí)現(xiàn)了簡(jiǎn)單的即時(shí)推送
離線推送相關(guān)配置及簡(jiǎn)要介紹
離線配置-服務(wù)端:
要實(shí)現(xiàn)消息的離線推送,必然需要一個(gè)存儲(chǔ)臨時(shí)數(shù)據(jù)的部件
此處用到的是mongo,當(dāng)然可以根據(jù)需要選擇其他的存儲(chǔ)工具
server.js中的settings需更改為:
let settings = { port: 5112, persistence:{ //增加了此項(xiàng) factory: mosca.persistence.Mongo, url: "mongodb://localhost:27017/mosca" } }
factory: 引入mosca對(duì)特定存儲(chǔ)工具的一些處理方法
url: 其中的 27017 為mongo所監(jiān)聽的端口號(hào),mosca為存儲(chǔ)相關(guān)數(shù)據(jù)的數(shù)據(jù)庫(kù)
值得一提的是:配置好mongo的環(huán)境后,不需要提前在mongo中手動(dòng)創(chuàng)建,若數(shù)據(jù)庫(kù)不存在會(huì)自動(dòng)生成,而且mosca會(huì)為你作好其他一切基本事項(xiàng) (即:若只想臨時(shí)體驗(yàn)下效果,甚至可以暫時(shí)把mongo放一邊 )
在mongo中,可以看到自動(dòng)新添了db: mosca及其下的collection(相當(dāng)于關(guān)系型數(shù)據(jù)庫(kù)中的表/關(guān)系)
離線配置-客戶端:
pub.js和sub.js中的client中都可以改為:
let client = mqtt.connect('mqtt://localhost', { port: 5112, clientId: 'cli_**', clean: false//增加了此項(xiàng) })
- clientId: 區(qū)分客戶端的識(shí)別碼
- clean: 此處決定了客戶端在服務(wù)端的session是否會(huì)被清除,默認(rèn)為true,為實(shí)現(xiàn)離線推送,我們需要將其保留
- clean及上文中的persistence為實(shí)現(xiàn)離線推送的關(guān)鍵配置
mqtt.connect()會(huì)返回一個(gè)mqttClient對(duì)象,包含了:reconnect(), subscribe(), publish()等一系列方法。
本文中發(fā)送端接收端被分為了pub.js和sub.js兩個(gè)獨(dú)立文件,僅僅為了方便在不同控制臺(tái)中觀察效果
一個(gè)client可以既為推送端,又為訂閱端
至此,所有代碼已完成
其他介紹:
client.subscribe():
為本客戶端訂閱一個(gè)話題,所有訂閱此話題的用戶都會(huì)收到在此話題下推送的信息
//client.subscribe(topic,opts) client.subscribe('test',{qos:1})
opts中的qos為通信機(jī)制,控制發(fā)送端與接收端的互鎖程度
上文中的其中一個(gè)collection: subscriptions即記錄各用戶話題訂閱情況
用戶cli_sub及cli2_sub訂閱了話題test:
(新增一個(gè)cli2_pub,下文有用)
注:
重復(fù)執(zhí)行腳本sub.js實(shí)際上對(duì)topic進(jìn)行了重復(fù)訂閱
實(shí)際編碼時(shí),應(yīng)避免topic的重復(fù)訂閱,即使重復(fù)訂閱并不影響實(shí)現(xiàn)效果
client.publish():
向指定topic發(fā)送數(shù)據(jù)
message為Buffer或String格式,可以通過(guò)序列化或轉(zhuǎn)json實(shí)現(xiàn)對(duì)復(fù)雜數(shù)據(jù)對(duì)象的傳送
//client.publish(topic, message, opts, callback) let num = 0; setInterval(function (){ client.publish('test', 'Hello mqtt ' + (++num), {qos:1}, () => console.log(num)); }, 1000)
參數(shù)不再贅述
此處用一個(gè)定時(shí)器定時(shí)在 topic: test 下發(fā)送'Hello mqtt 1,2,3..'
用回調(diào)函數(shù)實(shí)時(shí)打印一下發(fā)送的num:
當(dāng)訂閱者處于離線狀態(tài)時(shí),可以在collection: packets中查看到臨時(shí)數(shù)據(jù)的存儲(chǔ)情況:
mosca把每一條推送消息為所有訂閱用戶都生成了獨(dú)立的記錄,用同一個(gè)messageId進(jìn)行關(guān)聯(lián)
當(dāng)其中一個(gè)用戶(cli2_sub)上線時(shí),獲取到其對(duì)應(yīng)的數(shù)據(jù),
而后數(shù)據(jù)庫(kù)中相應(yīng)記錄便會(huì)被刪除
此時(shí)僅有cli_sub用戶的數(shù)據(jù)
當(dāng)cli2_sub上線接收消息后,packets中記錄將被清空
client.on():
即在client上觸發(fā)的事件,此處只列舉消息接收事件
//client.on(event, callback) client.on('message', function (topic, message) { console.log('received message: ', message.toString()) })
處理為簡(jiǎn)單地打印到控制臺(tái)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
剖析Node.js異步編程中的回調(diào)與代碼設(shè)計(jì)模式
這篇文章主要介紹了Node.js異步編程中的回調(diào)與代碼設(shè)計(jì)模式,雖然大多數(shù)場(chǎng)合回調(diào)編寫時(shí)的長(zhǎng)串括號(hào)不怎么好看,但Node的異步性能確實(shí)很好,需要的朋友可以參考下2016-02-02如何用npm命令刪除開發(fā)項(xiàng)目中的node_modules文件夾
每個(gè)項(xiàng)目都會(huì)產(chǎn)生一個(gè)node_modules,每個(gè)node_modules少則幾十兆,多則幾百甚至上千兆,隨著時(shí)間的積累,維護(hù)項(xiàng)目的增加,整個(gè)項(xiàng)目目錄體積會(huì)越來(lái)越大,這篇文章主要給大家介紹了關(guān)于如何用npm命令刪除開發(fā)項(xiàng)目中的node_modules文件夾,需要的朋友可以參考下2023-12-12node實(shí)現(xiàn)socket鏈接與GPRS進(jìn)行通信的方法
這篇文章主要介紹了node實(shí)現(xiàn)socket鏈接與GPRS進(jìn)行通信的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05Express實(shí)現(xiàn)Session身份認(rèn)證的示例代碼
本文主要介紹了Express實(shí)現(xiàn)Session身份認(rèn)證的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01Node.js版本升級(jí)如何修改模塊默認(rèn)的保存位置
這篇文章主要給大家介紹了關(guān)于Node.js版本升級(jí)如何修改模塊默認(rèn)的保存位置,文中通過(guò)代碼以及圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用node.js具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-05-05詳解nodejs操作mongodb數(shù)據(jù)庫(kù)封裝DB類
這篇文章主要介紹了詳解nodejs操作mongodb數(shù)據(jù)庫(kù)封裝DB類,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Node.js實(shí)現(xiàn)爬取網(wǎng)站圖片的示例代碼
本文將利用Node.js開發(fā)一個(gè)小示例—爬取某圖片網(wǎng)站的圖片,文中涉及的知識(shí)點(diǎn)有https模塊、cheerio模塊、fs模塊和閉包,感興趣的可以了解一下2022-04-04