Как передать сокет в кластер в узле

Я хотел бы получить многопроцессорный узел. Рабочие слушают связи клиентов. Мне нужно передать сокеты для мастер-процесса, потому что мастер-процесс посылает сообщение клиентам. Рабочим также нужен сокет для отправки сообщений клиентам.

Сокет является круглым объектом и не может перейти в основной процесс.

Мой код:

const cluster = require('cluster');

const http = require('http');
var io = require('socket.io');

var users;
var clients = {};
if (cluster.isMaster) {

function messageHandler(msg) {
   if (msg.usersarray) {
      usersarray = msg.usersarray;
      console.log(usersarray);
   }else if(msg.socket){
      clients[usersarray["manu"][0]] = msg.socket;
      clients[usersarray["manu"][0]].emit("hola","hola");               
   }
}

// Start workers and listen for messages containing notifyRequest
const numCPUs = require('os').cpus().length;
for (var i = 0; i < numCPUs; i++) {
  cluster.fork();
}

Object.keys(cluster.workers).forEach((id) => {
  cluster.workers[id].on('message', messageHandler);
});


}else {

// Create server & socket

var server = http.createServer(function(req, res){
    // Send HTML headers and message
    res.writeHead(404, {'Content-Type': 'text/html'});
    res.end('<h1>Aw, snap! 404</h1>');
});
server.listen(3000);
io = io.listen(server);

// Add a connect listener
io.sockets.on('connection', function(socket) {
    var hs = socket.handshake;
    console.log("socket connected");    
    if(users == undefined){
        users = {};
    }

    if(hs.query.usuario != undefined){

        if(users[hs.query.usuario] == undefined){
            users[hs.query.usuario] = new Array();
        }    

        users[hs.query.usuario].push(socket.id); // connected user with its socket.id
        clients[socket.id] = socket; // add the client data to the hash
        process.send({ usersarray: users});
        process.send({ socket: socket});
    }

    // Disconnect listener
    socket.on('disconnect', function() {
        console.log('Client disconnected.');
    });
});
}

в строке process.send({ socket: socket}); Узел js получает ошибку "Ошибка типа: преобразование круговой структуры в JSON"

-Я использовал какой-то модуль для преобразования кругового объекта, но не работает.

-Я пытался передать идентификатор сокета, а затем в главном процессе создал новый сокет с этим идентификатором, но я не знал, чтобы его использовать.

Есть ли возможность передать сокет от рабочего к мастер-процессу?

Версия узла js: v5.5.0

2 ответа

Хм, я не думаю, что это возможно, что вы пытаетесь сделать. Когда вы создаете кластер, это означает, что вы создаете отдельные процессы (мастер + рабочие), которые могут общаться только по каналу.

Разговор по трубе означает, что они могут только посылать строки друг другу. process.send пытается сериализовать объект Javascript как JSON (-> делая из него строку), используя JSON.stringify. JSON, например, не может иметь функции, круги и т. Д. Я только что проверил socket объект, он очень сложный и содержит функции (такие как socket.emit()), поэтому вы не можете просто сериализовать его и отправить по каналу.

Может быть, вы можете проверить это или это о том, как использовать кластерные WebSockets.

Это не кажется очень тривиальным. Может быть, вы можете просто передать задачи с интенсивным использованием ЦП некоторым рабочим процессам (через кластер или просто порождать их самостоятельно), отправить результаты обратно мастеру и позволить ему осуществлять всю связь с клиентом?

Я понимаю вашу цель широковещательной передачи всем рабочим процессам узла в кластере, хотя вы не можете отправить компонент сокета как таковой, но для этой цели есть обходной путь. Я попробую объяснить на примере:

Шаг 1: когда клиентское действие требует трансляции:

Child.js (процесс, который был разветвлен):

socket.on("BROADCAST_TO_ALL_WORKERS", function (data) 
{
    process.send({cmd : 'BROADCAST_TO_ALL_WORKERS', message :data.message});
}) 

Шаг 2: На стороне создания кластера

Server.js (место, где происходит разветвление кластера):

if (cluster.isMaster) {

  for (var i = 0; i < numCPUs; i++) {

    var worker = cluster.fork();

    worker.on('message', function (data) {
     if (data.cmd === "BROADCAST_TO_ALL_WORKERS") {
       console.log(server_debug_prefix() + "Server Broadcast To All, Message : " + data.message + " , Reload : " + data.reload + " Player Id : " + data.player_id);
        Object.keys(cluster.workers).forEach(function(id) {
            cluster.workers[id].send({cmd : "BROADCAST_TO_WORKER", message : data.message});
        });
      }
    });
  }

  cluster.on('exit', function (worker, code, signal) {
    var newWorker = cluster.fork();
    newWorker.on('message', function (data) {
      console.log(data);
      if (data.cmd === "BROADCAST_TO_ALL_WORKERS") {
        console.log(data.cmd,data);
        Object.keys(cluster.workers).forEach(function(id) {
            cluster.workers[id].send({cmd : "BROADCAST_TO_WORKER", message : data.message});
        });
      }
    });
  });
} 
else {
  //Node Js App Entry
  require("./Child.js");
}

Шаг 3: Трансляция в дочернем процессе

-> Поместите это перед io.on("соединение") в Child.js

process.on("message", function(data){
    if(data.cmd === "BROADCAST_TO_WORKER"){



    io.sockets.emit("SERVER_MESSAGE", { message: data.message, reload: data.reload, player_id : data.player_id });
}
});

Я надеюсь, что это ясно. Пожалуйста, прокомментируйте, если это сбивает с толку... Я постараюсь объяснить это.

Другие вопросы по тегам