簡體   English   中英

帶有PubSub的Socket.io:刷新多頁后幾乎不顯示實時數據

[英]Socket.io with PubSub : Less to no real-time data displayed after multiple page refresh

我正在嘗試使用Google PubSub,Node js和Google App Engine可視化流數據。 我正在做的很簡單:

  1. 每1秒鍾將消息流推送到PubSub主題(使用python腳本)
  2. 創建該主題的訂閱
  3. 創建一個簡單的Web應用程序,偵聽訂閱,解析每個傳入消息,然后以實時條形圖的形式(使用node js,socket.io和Fusionchart)將其顯示給瀏覽器

我遵循了本教程: https ://www.fusioncharts.com/blog/visualize-real-time-data-socket-io-charts/,唯一的區別是,我還遵循以下文檔使用了PubSub而不是PubNub:對於“接收消息”部分, 請https://cloud.google.com/pubsub/docs/quickstart-client-libraries#pubsub-client-libraries-nodejs

實際上,當我每1秒發布10條消息時,圖表將每1秒實時准確顯示10條消息。 這是我運行應用程序時圖表的外觀:

可視化示例

問題是它僅在我第一次運行該應用程序並打開頁面時才起作用。 當我刷新頁面並推送另外10條新消息時,顯示數據所需的時間更長。 當它最終出現時,僅顯示10條消息中的5條。 如果我嘗試刷新同一頁面,則顯示的數據會越來越少,甚至有時什么都不會出現。

我通過控制台跟蹤每個傳入和傳出的消息,似乎一切正常。 已推送10條消息,收到10條消息。 只是出於某種原因,每次刷新后顯示的越來越少。

這是我的app.js代碼:

 var express = require('express'); var app = require('express')(); var http = require('http').Server(app); //creates a new socket.io instance attached to the http server. var io = require('socket.io')(http); // Imports the Google Cloud client library const PubSub = require('@google-cloud/pubsub'); // Your Google Cloud Platform project ID const projectId = 'myprojecthere'; //Provide the absolute path to the dist directory. app.use(express.static(__dirname + '/dist')); //On get request send 'index.html' page as a response. app.get('/', function(req, res) { res.sendFile(__dirname +'/index.html'); }); //Whenever someone connects this gets executed //original : connection io.on('connection', function (socket) { console.log(`Enter io connection`); console.log(' %s sockets connected', io.engine.clientsCount) // Instantiates a client const pubsub = new PubSub({ projectId: projectId, key: """censored""" }); var strData; /** * TODO(developer): Uncomment the following lines to run the sample. * https://cloud.google.com/pubsub/docs/pull#pubsub-pull-messages-async-nodejs */ const subscriptionName = 'testing_subscription'; const topicName = 'testing'; const timeout = 50; // References an existing subscription //var topic = pubsub.topic(topicName) const subscription = pubsub.subscription(subscriptionName); //Function to format time and date function formatDatetime (TimeStamp){ var formatted = (TimeStamp.getHours()) + ':' + (TimeStamp.getMinutes()) + ':' + (TimeStamp.getSeconds()) + ':' + (TimeStamp.getMilliseconds()); return formatted; } // Create an event handler to handle messages let messageCount = 0; const messageHandler = message => { console.log(`Received message: ${message.id}`); console.log(`\\tData: ${message.data}`); console.log(`\\tAttributes: ${message.attributes}`); var obj = JSON.parse(message.data); console.log(`\\tTimeStamp: ${obj.messages.timestamp}`); console.log(`\\tAmount: ${obj.messages.amount}`); messageCount += 1; console.log(`Message count : ${messageCount}`); message.ack(); console.log(`Message Acknowledged`); // This doesn't ack the message, but allows more messages to be retrieved // if your limit was hit or if you don't want to ack the message. // message.nack(); // Get creation timestamp var x = new Date(obj.messages.timestamp); // Time formatting for x-axis in chart var formatted = formatDatetime(x); var Count = obj.messages.amount; console.log(`Extracting Timestamp: ${formatted}`); console.log(`Counts : ${Count}`); strData = {"label": formatted, "value": Count } socket.emit('news', strData); console.log(``); }; // Listen for new messages until timeout is hit subscription.on(`message`, messageHandler); setTimeout(() => { console.log(`Enter timeout`); //subscription.removeListener('message', messageHandler); console.log(`0 message(s) received.`); var x = new Date(); var formatted = formatDatetime(x); var Count = 0; console.log(`Extracting Timestamp: ${formatted}`) strData = {"label": formatted, "value": Count } console.log(`strData : ${strData}`) console.log(``); socket.emit('news', strData); }, timeout); //other handling if ( typeof strData == 'undefined') { console.log(`Something else happened`) var x = new Date(); var formatted = formatDatetime(x); console.log(`Extracting Timestamp: ${formatted}`) strData = {"label": formatted, "value": 9 } socket.emit('news', strData); } console.log(`strData : ${strData}`); console.log(``); }); //server listening on port 8080 http.listen(8080, function() { console.log('listening on *:8080'); }); 

這是我用來顯示圖表的代碼:

 /*globals io */ var FusionCharts = require("fusioncharts"); require("fusioncharts/fusioncharts.charts")(FusionCharts); require("fusioncharts/fusioncharts.widgets")(FusionCharts); var socket = io(); var transactionChart = new FusionCharts({ id: "mychart", type: 'realtimecolumn', width: '700', height: '350', dataFormat: 'json', dataSource: { "chart": { "caption": "Streaming Data Visualization", "subCaption": "Testing", "yaxismaxvalue": "10", "numdisplaysets": "10", "yAxisName":"Quantity", "labeldisplay": "rotate", "showLegend":"0", "showValues": "0", "numbersuffix": "Kg", "showlabels": "1", /*This parameter lets you set whether you want the latest value (received from server) to be displayed on the chart or not*/ "showRealTimeValue": "0", /*For this parameter, you can specify the number of seconds after which the chart will look for new data. This process will happen continuously - ie, if you specify 5 seconds here, the chart will look for new data every 5 seconds*/ "refreshInterval":".1", /*If you want the chart to keep polling for new data every x seconds and queue it, you can specify that x seconds as updateInterval. This helps you poll at different intervals and then draw at another interval (specified as refreshInterval)*/ "updateInterval":".1", "yAxisNamePadding":"10", //Cosmetics "paletteColors" : "#0075c2,#1aaf5d", "baseFontColor" : "#333333", "baseFont" : "Helvetica Neue,Arial", "captionFontSize" : "14", "subcaptionFontSize" : "14", "subcaptionFontBold" : "0", "showBorder" : "0", "bgColor" : "#ffffff", "showShadow" : "0", "canvasBgColor" : "#ffffff", "canvasBorderAlpha" : "0", "divlineAlpha" : "100", "divlineColor" : "#999999", "divlineThickness" : "1", "divLineIsDashed" : "1", "divLineDashLen" : "1", "divLineGapLen" : "1", "usePlotGradientColor" : "0", "showplotborder" : "0", "valueFontColor" : "#ffffff", "placeValuesInside" : "1", "rotateValues" : "1", "showXAxisLine" : "1", "xAxisLineThickness" : "1", "xAxisLineColor" : "#999999", "showAlternateHGridColor" : "0", "legendBgAlpha" : "0", "legendBorderAlpha" : "0", "legendShadow" : "0", "legendItemFontSize" : "10", "legendItemFontColor" : "#666666" }, "categories": [ { "category": [ { "label": "Start" } ] } ], "dataset": [ { "seriesname": "", "alpha": "100", "data": [ { "value": "3" } ] } ] } }).render("chart-container"); //On connection with socket, will start receiving the data socket.connect('http://localhost:8080/'); socket.on('news', function (data) { function updateData() { //Converting the fetched data in FusionCharts format var strData = "&label=" + data.label + "&value=" + data.value; //feeding the data to the real time chart FusionCharts.items.mychart.feedData(strData); } //calling the update method updateData(); }); 

這是我的index.html代碼:

 <!DOCTYPE html> <html> <head> <title>Hello world</title> <script src="/socket.io/socket.io.js"></script> </head> <body> <div id="chart-container">FusionCharts will render here</div> <script src="bundle.js"></script> </body> </html> 

我對Javascript還是很陌生,以前從未在Web應用程序上工作過。 我可能錯過了事情的運作方面的重要知識。 但是我不確定,盡管我不確定。

可能是因為每次刷新頁面時都會建立一個新的套接字連接,而以前的連接實際上收到了丟失的消息(因此不顯示)嗎?

我嘗試過但仍然無法解決的一些解決方案: Node.js Socket.io頁面刷新多個連接

有人可以幫我嗎?

我碰巧找到了解決我自己問題的解決方案。

不能完全確定為什么,但是這是發生了什么:每當刷新頁面時,舊的套接字連接都會斷開,並創建新的套接字連接。 這個新的套接字將監聽相同的訂閱。

盡管在頁面刷新期間舊套接字的狀態似乎已斷開,但是由於某種原因,它仍在偵聽相同的訂閱。 這將導致10條消息在兩個或多個連接之間分配(取決於刷新多少頁)。

但是,瀏覽器上顯示的只是最新的連接。 這看起來好像消息丟失了,而實際上它們分散在許多(看不見的)連接上。 很明顯,當我嘗試打印最終以每條消息結尾的“套接字ID”時。

因此,我所做的基本上是在套接字斷開連接期間添加了一些小處理:

//on Disconnect
socket.on('disconnect', function () {
console.log("LOG: just disconnected: " + socket.id);
subscription.removeListener('message', messageHandler);

因此,每當套接字斷開連接時,它也將停止監聽訂閱,並且新套接字將收到一整套消息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM