node實(shí)現(xiàn)socket鏈接與GPRS進(jìn)行通信的方法
業(yè)務(wù)背景
最近接到一個(gè)需求,在微信公眾號(hào)界面設(shè)計(jì)一個(gè)獨(dú)立界面,界面上有 A 電機(jī)進(jìn)、A 電機(jī)退、B 電機(jī)進(jìn)、B 電機(jī)退 4 個(gè)按鈕,點(diǎn)擊對(duì)應(yīng)按鈕,云平臺(tái)發(fā)送不同的代碼給電機(jī)本地的控制器,控制電機(jī)執(zhí)行不同的動(dòng)作,電機(jī)本地控制器具備GPRS網(wǎng)絡(luò)功能。服務(wù)器與電機(jī)本地控制器(客戶(hù)端)采用 TCP 協(xié)議連接,客戶(hù)端發(fā)送心跳包給服務(wù)器保持長(zhǎng)連接,客戶(hù)端每次收到服務(wù)器下發(fā)的代碼指令后作出回復(fù)主要的實(shí)現(xiàn)原理是前端訪(fǎng)問(wèn)后臺(tái)的接口傳輸數(shù)據(jù)。后臺(tái)采用用socket與GPRS模塊進(jìn)鏈接,暴露出一個(gè)IP+PORT給GPRS進(jìn)行訪(fǎng)問(wèn)即可,實(shí)現(xiàn)邏輯比較簡(jiǎn)單。但是在開(kāi)發(fā)中出現(xiàn)一下比較棘手問(wèn)題,下面進(jìn)行一一歸納。
技術(shù)棧
主要采用的技術(shù)棧前端部分采用vue和weUI,后臺(tái)采用node的koa框架,前端頁(yè)面是直接寫(xiě)在koa里面,由于頁(yè)面比較簡(jiǎn)單,所以沒(méi)有實(shí)現(xiàn)前后的分離。
實(shí)現(xiàn)過(guò)程
1、前端部分
前端部分實(shí)現(xiàn)主要是提供4個(gè)按鈕,向后臺(tái)接口請(qǐng)求對(duì)應(yīng)的數(shù)據(jù),例如:點(diǎn)擊A點(diǎn)擊前進(jìn),就向后臺(tái)請(qǐng)求http://XXXX:4000/djxt/move接口并傳輸數(shù)據(jù),可以下載完整項(xiàng)目運(yùn)行后,通過(guò)127.0.0.1:3002/djxt進(jìn)行訪(fǎng)問(wèn),頁(yè)面html代碼主要部分如下:
<div class="wrap"> <button @click="goA('A1')" class="weui-btn" v-bind:class="{ 'weui-btn_loading': btnStatus.cur == 'A1'&&btnStatus.status==0, 'weui-btn_primary': btnStatus.cur == 'A1'&&btnStatus.status==1, 'weui-btn_plain-primary': btnStatus.cur != 'A1' }">A 前進(jìn)<i v-show="btnStatus.cur == 'A1'&&btnStatus.status==0" class="weui-loading"></i></button> <button @click="backA('A0')" class="weui-btn" v-bind:class="{ 'weui-btn_loading': btnStatus.cur == 'A0'&&btnStatus.status==0, 'weui-btn_primary': btnStatus.cur == 'A0'&&btnStatus.status==1, 'weui-btn_plain-default': btnStatus.cur != 'A0' }">A 后退<i v-show="btnStatus.cur == 'A0'&&btnStatus.status==0" class="weui-loading"></i></button> <button @click="goB('B1')" class="weui-btn" v-bind:class="{ 'weui-btn_loading': btnStatus.cur == 'B1'&&btnStatus.status==0, 'weui-btn_primary': btnStatus.cur == 'B1'&&btnStatus.status==1, 'weui-btn_plain-primary': btnStatus.cur != 'B1' }">B 前進(jìn)<i v-show="btnStatus.cur == 'B1'&&btnStatus.status==0" class="weui-loading"></i></button> <button @click="backB('B0')" class="weui-btn" v-bind:class="{ 'weui-btn_loading': btnStatus.cur == 'B0'&&btnStatus.status==0, 'weui-btn_primary': btnStatus.cur == 'B0'&&btnStatus.status==1, 'weui-btn_plain-default': btnStatus.cur != 'B0' }">B 后退<i v-show="btnStatus.cur == 'B0'&&btnStatus.status==0" class="weui-loading"></i></button> </div>
發(fā)送數(shù)據(jù)給后臺(tái)部分代碼如下:
// A 前進(jìn) goA (id){ axios.post('/djxt/move', { id }) .then( (response)=> { console.log(response); if( response.data.success ){ this.alertDialog.content = '操作成功'; this.alertDialog.status = true; }else{ this.alertDialog.content = '操作失敗了'; this.alertDialog.status = true; } }) .catch( (error)=> { console.log(error); this.alertDialog.content = '操作失敗了'; this.alertDialog.status = true; }); }
2、后臺(tái)實(shí)現(xiàn)
由于用的是node技術(shù)棧,當(dāng)初使用的是scoket.io來(lái)進(jìn)行scoket鏈接的,但是在后面的開(kāi)發(fā)中發(fā)現(xiàn)該方法需要有一個(gè)事件去觸發(fā)提交數(shù)據(jù),在客戶(hù)端也需要有事件進(jìn)行監(jiān)聽(tīng),不適合在與GPRS進(jìn)行通信,最后無(wú)奈的放棄了。后面采用了node的NET模塊進(jìn)行通信,該模塊只要調(diào)用write(data)就可以發(fā)送綁定端口的數(shù)據(jù)。相對(duì)比較簡(jiǎn)單??梢詤⒖家幌耼odejs.org/dist/latest… 看不懂英文可以找中文版的。
net的連接可以寫(xiě)在www文件或是app.js文件,看自己需求。在該項(xiàng)目中暴露出來(lái)接口127.0.0.1:3004,代碼如下:
//socket var net = require('net'); // 服務(wù)器IP var HOST = '127.0.0.1'; // 端口號(hào) var PORT = 3004; // 創(chuàng)建一個(gè)TCP服務(wù)器實(shí)例,調(diào)用listen函數(shù)開(kāi)始監(jiān)聽(tīng)指定端口 // 傳入net.createServer()的回調(diào)函數(shù)將作為”connection“事件的處理函數(shù) // 在每一個(gè)“connection”事件中,該回調(diào)函數(shù)接收到的socket對(duì)象是唯一的 net.createServer(function(sock) { // 全局sock,可以在其他地方調(diào)用 global.sock = sock // 獲得了一個(gè)socket連接,將客戶(hù)端輸出來(lái) console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort); // 為這個(gè)socket實(shí)例添加一個(gè)"data"事件處理函數(shù),接收客戶(hù)端數(shù)據(jù) sock.on('data', function(data) { console.log('DATA ' + sock.remoteAddress + ': ' + data); // 回發(fā)該數(shù)據(jù),客戶(hù)端將收到來(lái)自服務(wù)端的數(shù)據(jù),實(shí)現(xiàn)ECHO服務(wù)器 // sock.write('' + data ); }); // 為這個(gè)socket實(shí)例添加一個(gè)"close"事件處理函數(shù) sock.on('close', function(data) { console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort); }); }).listen(PORT, HOST);
代碼中的HOST 是你需要暴露給GPRS模塊的ip,PORT是端口。net.createServer創(chuàng)建服務(wù)后,它回調(diào)里面的sock可以用來(lái)做一些監(jiān)聽(tīng),例如客戶(hù)端返回?cái)?shù)據(jù)sock.on('data', function(data) {})。在開(kāi)發(fā)過(guò)程中遇到一個(gè)問(wèn)題就是HOST在本地是用127.0.0.1是可以進(jìn)行訪(fǎng)問(wèn)的,但是到了云服務(wù)后,會(huì)出現(xiàn)端口訪(fǎng)問(wèn)不了。解決辦法是把HOST改為你自己服務(wù)器的內(nèi)網(wǎng)ip即可進(jìn)行訪(fǎng)問(wèn)。global.sock = sock這個(gè)主要是暴露全局的sock,可以在其他需要地方進(jìn)行調(diào)用,切記要暴露出去。
服務(wù)端處理前端發(fā)送過(guò)來(lái)的數(shù)據(jù),發(fā)送到GPRS模塊。該項(xiàng)目中前端訪(fǎng)問(wèn)的路由為/move,進(jìn)入這個(gè)路由后進(jìn)行判斷,再把值轉(zhuǎn)發(fā)給GPRS,這里關(guān)鍵點(diǎn)是利用全局的Sock的sock.write()來(lái)發(fā)送到客戶(hù)端。代碼如下
//前端接口 router.post('/move', async (ctx, next) => { let params = ctx.request.body; // console.log('ctx.state: ', global.sock) // console.log('ctx.state2222: ', sock) console.log('前端接口: ', params) if( !sock ){ ctx.body = { data: params, success: false, msg: 'socket不存在' } }else{ sock.write( params.id ); ctx.body = { data: params, success: true, msg: '' } } })
完整的代碼可參考github。https://github.com/bayi-lzp/node_djxt_socket
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 基于Node.js和Socket.IO實(shí)現(xiàn)實(shí)時(shí)通信功能
- 淺析如何在Bash中調(diào)用Node運(yùn)行JS文件進(jìn)行數(shù)據(jù)通信
- Node.js中的進(jìn)程間通信
- 基于node的tcp客戶(hù)端和服務(wù)端的簡(jiǎn)單通信
- Node與Python 雙向通信的實(shí)現(xiàn)代碼
- Nodejs環(huán)境實(shí)現(xiàn)socket通信過(guò)程解析
- node 利用進(jìn)程通信實(shí)現(xiàn)Cluster共享內(nèi)存
- Node.js進(jìn)行串口通信的實(shí)現(xiàn)示例
相關(guān)文章
Node.JS段點(diǎn)續(xù)傳:Nginx配置文件分段下載功能的實(shí)現(xiàn)方法
在Node.JS中可以配置這個(gè)標(biāo)簽來(lái)實(shí)現(xiàn)文件的分段下載。這篇文章給大家介紹了Node.JS段點(diǎn)續(xù)傳:Nginx配置文件分段下載功能的實(shí)現(xiàn)方法,需要的朋友參考下吧2018-03-03node+express+ejs制作簡(jiǎn)單頁(yè)面上手指南
本文記錄了使用node+express+ejs制作簡(jiǎn)單頁(yè)面的全過(guò)程,話(huà)說(shuō)express+ejs真的是太難了,有種蛋蛋的憂(yōu)傷~2014-11-11對(duì)node.js中render和send的用法詳解
今天小編就為大家分享一篇對(duì)node.js中render和send的用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05Node.js?搭建后端服務(wù)器內(nèi)置模塊(?http+url+querystring?的使用)
這篇文章主要介紹了Node.js搭建后端服務(wù)器內(nèi)置模塊(http+url+querystring的使用),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容戒殺,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-09-09nodejs實(shí)例解析(輸出hello world)
本文主要介紹nodejs實(shí)例解析:輸出hello world的完整過(guò)程。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01Node.js EventEmmitter事件監(jiān)聽(tīng)器用法實(shí)例分析
這篇文章主要介紹了Node.js EventEmmitter事件監(jiān)聽(tīng)器用法,結(jié)合實(shí)例形式分析了EventEmmitter事件監(jiān)聽(tīng)器相關(guān)函數(shù)與使用技巧,需要的朋友可以參考下2019-01-01Node+Express連接MySQL實(shí)現(xiàn)增刪改查功能
這篇文章主要為大家詳細(xì)介紹了Node如何結(jié)合Express連接MySQL實(shí)現(xiàn)增刪改查功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-05-05