2017-11-02 67 views
7

Implementacja socket.io, którą zrobiłem, jest nieprawidłowa. Próbuję wprowadzić długi polling na danych mysql.Serwer nodejs- socket.io przesyła te same dane wszystkim użytkownikom.

W tym wydaniu pobieram dane użytkownika dla każdego użytkownika podłączonego do utworzonego przez siebie serwera z długim pollingiem. Każdy użytkownik przekaże swój unikalny identyfikator użytkownika do serwera w celu pobrania danych, które go dotyczą. (W prawdziwej aplikacji chcę otrzymywać powiadomienia użytkowników)

Użytkownicy łączą się z serwerem, a serwer wykonuje również długie polling z DB. Problem polega jednak na tym, że te same dane są przesyłane do klienta, mimo że przekazuję unikalne identyfikatory od strony klienta.

Użytkownik 1 przeszedł ID 5 i użytkownik 2 przechodzi id 3. Obie te użytkownicy otrzymują te same dane jak odpowiedzi (1 użytkownika na dane)

oto klient kodu po stronie:

var user_id = 5; //hardcoded for now, but in real its fetched from a form 
var params = { 
    userId: user_id, 
}; 
// create a new websocket 
var socket = io.connect('http://localhost:8000', { query: params }); 

// on message received we print all the data inside the #container div 
socket.on('notification', function (data) { 
    console.log(data); 

}); 

Tu jest kod po stronie serwera:

var app = require('http').createServer(handler), 
    io = require('socket.io').listen(app), 
    fs = require('fs'), 
    mysql = require('mysql'), 
    connectionsArray = [], 
    connection = mysql.createConnection({ 
     host: 'localhost', 
     user: 'root', 
     password: '', 
     database: 'dumydb', 
     port: 3306 
    }), 
    POLLING_INTERVAL = 5000, 
    pollingTimer; 

// If there is an error connecting to the database 
connection.connect(function (err) { 
    // connected! (unless `err` is set) 
    if (err) { 
     console.log(err); 
    } 
}); 

// creating the server (localhost:8000) 
app.listen(8000); 

// on server started we can load our client.html page 
function handler(req, res) { 
    fs.readFile(__dirname + '/client.html', function (err, data) { 
     if (err) { 
      console.log(err); 
      res.writeHead(500); 
      return res.end('Error loading client.html'); 
     } 
     res.writeHead(200); 
     res.end(data); 
    }); 
} 

// creating a new websocket to keep the content updated without any AJAX request 
io.sockets.on('connection', function (socket) { 

    var userId = socket.handshake.query.userId; 
    // starting the loop only if at least there is one user connected 
    if (!connectionsArray.length) { 
     pollingLoop(userId); 
    } 

    socket.on('disconnect', function() { 
     var socketIndex = connectionsArray.indexOf(socket); 
     console.log('socketID = %s got disconnected', socketIndex); 
     if (~socketIndex) { 
      connectionsArray.splice(socketIndex, 1); 
     } 
    }); 

    console.log('A new socket is connected!'); 
    connectionsArray.push(socket); 

}); 

var pollingLoop = function (userId) { 
    var params = [userId]; 
    // Doing the database query 
    var tempQuery = `SELECT full_name FROM users WHERE id=?`; 
    var query = connection.query(tempQuery, params), 
     users = []; // this array will contain the result of our db query 

    // setting the query listeners 
    query 
     .on('error', function (err) { 
      // Handle error, and 'end' event will be emitted after this as well 
      updateSockets(err); 
     }) 
     .on('result', function (user) { 
      // it fills our array looping on each user row inside the db 
      users.push(user); 
     }) 
     .on('end', function() { 
      // loop on itself only if there are sockets still connected 
      if (connectionsArray.length) { 

       pollingTimer = setTimeout(function() { pollingLoop(userId) }, POLLING_INTERVAL); 

       updateSockets({ 
        users: users 
       }); 
      } else { 
       console.log('The server timer was stopped because there are no more socket connections on the app') 
      } 
     }); 
}; 

var updateSockets = function (data) { 
    // adding the time of the last update 
    data.time = new Date(); 
    // sending new data to all the sockets connected 
    connectionsArray.forEach(function (tmpSocket) { 
     tmpSocket.volatile.emit('notification', data); 
    }); 
}; 

console.log('Please use your browser to navigate to http://localhost:8000'); 

jest to poradnik Obserwuję: Link

Czy ktoś może mi pomóc dowiedzieć się, dlaczego te same dane są przesyłane do wszystkich użytkowników? Dzięki!

UPDATE 1

Próbowałem rozwiązania przewidziane przez Theo i Abdul Rab Memon zmieniłem updateSockets(), ale teraz dane jest wciśnięty tylko do pierwszego klienta podłączonego. Zrobiłem console.log() spojrzeć na to:

enter image description here

UPDATE 2:package.json

{ 
    "name": "nodejs-MySQL-push-notifications-demo", 
    "version": "1.0.0", 
    "description": "nodejs-MySQL-push-notifications-demo", 
    "main": "server.js", 
    "dependencies": { 
    "express": "^4.16.2", 
    "mysql": "~2.5.4", 
    "socket.io": "~1.3.2" 
    }, 
    "devDependencies": {}, 
    "scripts": { 
    "test": "echo \"Error: no test specified\" && exit 1", 
    "start": "node server.js" 
    }, 
    "repository": { 
    "type": "git", 
    "url": "git://github.com/GianlucaGuarini/nodejs-MySQL-push-notifications-demo.git" 
    }, 
    "author": "Gianluca Guarini", 
    "license": "BSD-2-Clause", 
    "bugs": { 
    "url": "https://github.com/GianlucaGuarini/nodejs-MySQL-push-notifications-demo/issues" 
    }, 
    "homepage": "https://github.com/GianlucaGuarini/nodejs-MySQL-push-notifications-demo" 
} 
+0

Funkcja updateSockets emituje zdarzenie powiadomienia o wszystkich gniazdach, więc te same dane są przesyłane do wszystkich użytkowników. –

+0

, więc co powinienem tam zmienić? Jestem całkiem nowy w tych rzeczach. @ Cr. 25 – Annabelle

+0

@AnnaBelle, czy możesz dostarczyć repozytorium git do debugowania? Ponieważ najlepiej jest używać dokładnie tych pakietów, z których korzystasz. –

Odpowiedz

2

Skoro wspomniałeś, że chcesz pobrać dane dotyczące tej użytkownik, musisz emitować do określonego gniazda klienta . Aby to zrobić, musisz zapisać plik socket.id klienta przy każdym połączeniu. Można to zrobić z mniej więcej tak:

var userList = {}; 

io.on('connection', (socket) => { 
    usersList[socket.handshake.query.userId].socket_id = socket.id; 
}); 

Po udanym odpytywania, możesz wysłać do konkretnego użytkownika jak to
Uwaga parametru dodatkowego identyfikatora użytkownika, który można przekazać z pollingLoop

var updateSockets = function (data, userId) { 
    // adding the time of the last update 
    data.time = new Date(); 
    // sending new data to the specific socket connected 
    io.sockets.to(userList[userId].socket_id).emit('notification', data); 
}; 

Możesz spróbować użyć przestrzeni nazw lub pomieszczeń, aby wysłać je do grupy.więc zamiast

connectionsArray.forEach(function (tmpSocket) { 
    tmpSocket.volatile.emit('notification', data); 
}); 

można użyć nazw

kod Client

var socket = io.connect('http://localhost:8000/your_name_space', { query: params }); 

kod Server

io.of('/your_name_space').emit('notification', data_to_be_sent); 

lub grupy - Proszę odnieść się do tego linku, aby uzyskać więcej informacji o pokojach https://socket.io/docs/rooms-and-namespaces/

+0

To nie zadziałało. socket.id jest niezdefiniowany. @Theo – Annabelle

+0

jakiej wersji socket.io używasz? ma zawierać losowy hash. – Theo

+0

socket.io-client: 2.0.4. Otrzymuję identyfikator gniazda po stronie klienta za pomocą tego kodu: socket.on ('connect',() => {socketId = socket.id;}); Ale nie dostaję tego samego po stronie serwera. – Annabelle

4
var app = require('http').createServer(handler), 
    io = require('socket.io').listen(app), 
    fs = require('fs'), 
    mysql = require('mysql'), 
    connectionsArray = [], 
    connection = mysql.createConnection({ 
     host: 'localhost', 
     user: 'root', 
     password: '', 
     database: 'dumydb', 
     port: 3306 
    }), 
    POLLING_INTERVAL = 5000, 
    pollingTimer; 

// If there is an error connecting to the database 
connection.connect(function (err) { 
    // connected! (unless `err` is set) 
    if (err) { 
     console.log(err); 
    } 
}); 

// creating the server (localhost:8000) 
app.listen(8000); 

// on server started we can load our client.html page 
function handler(req, res) { 
    fs.readFile(__dirname + '/client.html', function (err, data) { 
     if (err) { 
      console.log(err); 
      res.writeHead(500); 
      return res.end('Error loading client.html'); 
     } 
     res.writeHead(200); 
     res.end(data); 
    }); 
} 

// creating a new websocket to keep the content updated without any AJAX request 
io.sockets.on('connection', function (socket) { 

    var userId = socket.handshake.query.userId; 
    connectionsArray.push(socket); 
    // starting the loop only if at least there is one user connected 
    if (connectionsArray.length) { 
     var socketIndex = connectionsArray.indexOf(socket); 
     pollingLoop(userId, socketIndex); 
    } 

    socket.on('disconnect', function() { 
     var socketIndex = connectionsArray.indexOf(socket); 
     console.log('socketID = %s got disconnected', socketIndex); 
     if (~socketIndex) { 
      connectionsArray.splice(socketIndex, 1); 
     } 
    }); 

    console.log('A new socket is connected!'); 

}); 

var pollingLoop = function (userId, socketIndex) { 
    var params = [userId]; 
    // Doing the database query 
    var tempQuery = `SELECT full_name FROM users WHERE id=?`; 
    var query = connection.query(tempQuery, params), 
     users = []; // this array will contain the result of our db query 

    // setting the query listeners 
    query 
     .on('error', function (err) { 
      // Handle error, and 'end' event will be emitted after this as well 
      updateSockets(err, socketIndex); 
     }) 
     .on('result', function (user) { 
      // it fills our array looping on each user row inside the db 
      users.push(user); 
     }) 
     .on('end', function() { 
      // loop on itself only if there are sockets still connected 
      if (connectionsArray.length) { 

       pollingTimer = setTimeout(function() { pollingLoop(userId) }, POLLING_INTERVAL); 

       updateSockets({ 
        users: users 
       }, socketIndex); 
      } else { 
       console.log('The server timer was stopped because there are no more socket connections on the app') 
      } 
     }); 
}; 

var updateSockets = function (data, socketIndex) { 
    // adding the time of the last update 
    data.time = new Date(); 
    // sending new data to all the sockets connected 
    connectionsArray[socketIndex].volatile.emit('notification', data); 
}; 

console.log('Please use your browser to navigate to http://localhost:8000'); 

W metodzie updateSockets jesteś iteracji nad connectionsArray i emitujących „powiadomienie” zdarzenie z danymi na temat każdego gniazda, które jest obecne w connectionsArray, musisz przekazać gniazdo z socket.on ('connection', callback (socket)) do metody pollingLoop iz metody pollingLoop do updatSocket.

+0

To nie działa, nie wiem dlaczego. Testuję to z wielu przeglądarek na moim komputerze. Gniazdo zwraca dane wyjściowe tylko do pierwszej przeglądarki, która się łączy. Nawiązałem połączenie z przeglądarek Chrome, Firefox i Firefox. Dane wyjściowe są wysyłane tylko do jednego z nich. @Abdul Rab Memon – Annabelle

+0

socket.volatile.emit ("powiadomienie", dane); z twojego kodu emituje dane tylko do pierwszego podłączonego gniazdka. Nie przesyła danych do innych podłączonych gniazd. Podejście, o którym wspomniałeś, jest dobre tylko wtedy, gdy istnieje jedno aktywne połączenie. @Abdul Rab Memon – Annabelle

+0

Wyniki, które otrzymujesz, nie spodziewałem się, szczerze mówiąc, nie rozumiem, dlaczego tak się dzieje. Nie mogę uruchomić tego kodu, dopóki nie dostarczysz mi do tego pliku package.json. Edytowałem kod, spróbuj, jeśli to działa. @ AnnaBelle –