国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Node.js實(shí)現(xiàn)數(shù)據(jù)推送

2019-11-20 10:15:59
字體:
供稿:網(wǎng)友

場景:后端更新數(shù)據(jù)推送到客戶端(Java部分使用Tomcat服務(wù)器)。

后端推送數(shù)據(jù)的解決方案有很多,比如輪詢、Comet、WebSocket。

1. 輪詢對于后端來說開發(fā)成本最低,就是按照傳統(tǒng)的方式處理Ajax請求并返回?cái)?shù)據(jù),在學(xué)校的時(shí)候?qū)嶒?yàn)室的項(xiàng)目一直都采用輪詢,因?yàn)樗畋kU(xiǎn)也最容易實(shí)現(xiàn)。但輪詢帶來的通信資源的浪費(fèi)是無法忽視的,無論數(shù)據(jù)是否改變,都照常發(fā)送請求并響應(yīng),而且每次HTTP請求都帶有很長的頭部信息。

2. Comet的概念是長連接,客戶端發(fā)送請求后,后端將連接保持下來,直到連接超時(shí)或后端返回?cái)?shù)據(jù)時(shí)再重新建立連接,有效的將通信資源轉(zhuǎn)移到了服務(wù)器上,實(shí)際消耗的是服務(wù)器資源。

3. WebSocket是HTML5提供的一種全雙工通信技術(shù),通過“握手”實(shí)現(xiàn)客戶端與服務(wù)器之間的通信,實(shí)時(shí)性好,攜帶的頭部也較小,目前支持的瀏覽器如下:

理想的情況是采取WebSocket與Comet結(jié)合的方式,對IE8等瀏覽器采取Comet方式,做降級處理。但是這樣一來,后端需要實(shí)現(xiàn)兩種處理請求的邏輯,即WebSocket與Comet。所以,本文加入Node.js,之所以這樣做,是將處理WebSocket(或Comet)的邏輯轉(zhuǎn)移到Node.js部分,不給后端“添麻煩”,因?yàn)樵趯?shí)際情況下,前端開發(fā)人員推動(dòng)后端開發(fā)人員并不容易。Node.js作為瀏覽器與Java業(yè)務(wù)邏輯層通信的中間層,連接客戶端與Tomcat,通過Socket與Tomcat進(jìn)行通信(是Socket,不是WebSocket,后端需要實(shí)現(xiàn)Socket接口。

在客戶端,WebSocket與Comet通過Socket.io實(shí)現(xiàn),Socket.io會(huì)針對不同的瀏覽器版本或者不同客戶端選擇合適的實(shí)現(xiàn)方式(WebSocket, long pull..),Socket.io的引入讓處理WebSocket(或長連接)變的很容易。Socket.io

客戶端引入socket.io:

<script src="static/js/socket.io.js"></script>
客戶端JavaScript代碼:

 var socket = io.connect('127.0.0.1:8181'); // 發(fā)送數(shù)據(jù)至服務(wù)器socket.emit('fromWebClient', jsonData);// 從服務(wù)器接收數(shù)據(jù) socket.on('pushToWebClient', function (data) {  // do sth. });

Node.js服務(wù)器代碼:

 var http = require('http'),   app = http.createServer().listen('8181'),   io = require('socket.io').listen(app); io.sockets.on('connection', function (socketIO) {   // 從客戶端接收數(shù)據(jù)   socketIO.on('fromWebClient', function (webClientData) {     // do sth.   });   // 客戶端斷開連接   socketIO.on('disconnect', function () {     console.log('DISCONNECTED FROM CLIENT');   });       // 向客戶端發(fā)送數(shù)據(jù)   socketIO.emit('pushToWebClient', jsonData);   });

建立好客戶端同Node.js服務(wù)器的連接只是第一步,下面還需要建立Node.js服務(wù)器與Java業(yè)務(wù)邏輯層的聯(lián)系。這時(shí),Node.js服務(wù)器則作為客戶端,向Tomcat發(fā)送TCP連接請求。連接成功后,Node.js服務(wù)器和Tomcat建立了一條全雙工的通道,而且是唯一的一條,不論有多少個(gè)客戶端請求,都從Node.js服務(wù)器轉(zhuǎn)發(fā)至Tomcat;同樣,Tomcat推送過來的數(shù)據(jù),也經(jīng)由Node.js服務(wù)器分發(fā)至各個(gè)客戶端。

這里存在一個(gè)問題,就是在WebSocket連接與Socket連接都建立好之后,兩次連接彼此之間是屏蔽的。Tomcat不知道是哪次WebSocket連接發(fā)送過來的數(shù)據(jù),也不知道是哪個(gè)客戶端發(fā)來的數(shù)據(jù)。當(dāng)然,Node.js可以利用session id發(fā)送至Tomcat來標(biāo)識(shí)是哪一個(gè)客戶端,但本文采用的是另外一種辦法。

客戶端同Node.js建立WebSocket連接時(shí),每個(gè)連接都會(huì)包含一個(gè)實(shí)例,這里稱它為socketIO。每個(gè)socketIO都有一個(gè)id屬性用來唯一標(biāo)識(shí)這個(gè)連接,這里稱它為socket_id。利用socket_id,在Node.js服務(wù)器建立一個(gè)映射表,存儲(chǔ)每一個(gè)socketIO與socket_id的映射關(guān)系。Node.js服務(wù)器發(fā)送數(shù)據(jù)給Tomcat時(shí)帶上這個(gè)socket_id,再由Java部分進(jìn)行一系列處理以后封裝好每個(gè)客戶端需要的不同數(shù)據(jù)一并返回,返回的數(shù)據(jù)里要有與socket_id的對應(yīng)關(guān)系。這樣,Node.js服務(wù)器收到Tomcat發(fā)來的數(shù)據(jù)時(shí),通過前面提到的映射表由不同的socketIO分發(fā)至不同的客戶端。

Node.js服務(wù)器代碼:

 var http = require('http'),   net = require('net'),   app = http.createServer().listen('8181'),   io = require('socket.io').listen(app),   nodeServer = new net.Socket(); // 連接到Tomcat nodeServer.connect(8007, '127.0.0.1', function() {   console.log('CONNECTED'); });// 存儲(chǔ)客戶端的WebSocket連接實(shí)例 var aSocket = {}; // 同客戶端建立連接 io.sockets.on('connection', function (socketIO) {  // 從客戶端接收數(shù)據(jù),然后發(fā)送至Tomcat   socketIO.on('fromWebClient', function (webClientData) {        // 存儲(chǔ)至映射表     aSocket[socketIO.id] = socketIO;    // 發(fā)送至Tomcat的數(shù)據(jù)中添加socket_id    webClientData['sid'] = socketIO.id;        // 發(fā)送String類型的數(shù)據(jù)至Tomcat    nodeServer.write(JSON.stringify(webClientData));       });   // 客戶端斷開連接   socketIO.on('disconnect', function () {    console.log('DISCONNECTED FROM CLIENT');   });  }); // 從Tomcat接收數(shù)據(jù) nodeServer.on('data', function (data) {    var jsonData = JSON.parse(data.toString());     // 分發(fā)數(shù)據(jù)至客戶端   for (var i in jsonData.list) {     aSocket[jsonData.list[i]['sid']].emit('pushToWebClient', jsonData.list[i].data);  } });

上面的代碼省略了一些邏輯,比如Node.js服務(wù)器從Tomcat接收的數(shù)據(jù)分為兩種,一種是推送過來的數(shù)據(jù),另外一種是響應(yīng)請求的數(shù)據(jù),這里統(tǒng)一處理推送過來的數(shù)據(jù)。

在處理通信時(shí),Node.js發(fā)送至Tomcat的數(shù)據(jù)是String格式,而從Tomcat接收的數(shù)據(jù)為Buffer對象(8進(jìn)制),需要轉(zhuǎn)化為String之后再轉(zhuǎn)化為json發(fā)送至客戶端。

本文只是給出一個(gè)這樣兩次連接的簡單例子,具體的業(yè)務(wù)中需要加入許多東西。既然在項(xiàng)目中引入了Node.js,就需要前端承擔(dān)更多的事情,比如對數(shù)據(jù)的處理、緩存、甚至加入很多業(yè)務(wù)邏輯。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 阿合奇县| 军事| 开平市| 安多县| 台山市| 神农架林区| 蓬莱市| 泽州县| 屏东市| 德钦县| 冀州市| 吴旗县| 莱芜市| 高淳县| 丽江市| 东辽县| 德庆县| 贵南县| 九台市| 光泽县| 沁阳市| 筠连县| 曲松县| 尖扎县| 民丰县| 三原县| 桂阳县| 东莞市| 邹平县| 前郭尔| 安宁市| 漳州市| 神木县| 浙江省| 双柏县| 运城市| 讷河市| 中阳县| 巧家县| 南靖县| 保亭|