【问题标题】:Reconnect net.socket nodejs重新连接net.socket nodejs
【发布时间】:2014-11-05 15:18:51
【问题描述】:

我是 node.js 的新手,想连接到 TCP 套接字。为此,我使用了 net 模块。

我的想法是将连接序列包装到一个函数中,然后在“关闭”事件中尝试重新连接。显然没那么容易。

function conn() {

    client.connect(HOST_PORT, HOST_IP, function() {
        startSequence();
    })
}

client.on('close', function(e) {
    log('info','Connection closed! -> ' + e)
    client.destroy();
    setTimeout(conn(),1000);
});

因此,当远程主机关闭时,我看到我的日志正在通过,但是似乎正在发生的事情是,一旦远程主机上线,所有先前的尝试都开始得到处理 - 如果这有意义的话。如果您查看 client.connect,则有一个名为 startSequence 的函数发送一些数据,这些数据从远程服务器端“启动”连接。当服务器离线时,我开始重新连接之前所有失败的尝试似乎都已被缓冲,并在服务器上线时一起发送。

我也尝试过这个 Stackoverflow 链接中的代码,但无济于事 (Nodejs - getting client socket to try again after 5 sec time out)

client.connect(HOST_PORT, HOST_IP, function() {
    pmsStartSequence();
})


// Add a 'close' event handler for the client socket
client.on('close', function(e) {
    log('debug','connection  closed -> ' + e)
    client.setTimeout(10000, function() {
        log('debug', 'trying to reconnect')
        client.connect(HOST_PORT, HOST_IP, function() {
            pmsStartSequence();
        })
    })
});

对于失败后如何重新连接套接字有什么建议吗?

【问题讨论】:

  • 连接失败后客户端重新连接到服务器的更好方法,您可以使用以下方法: var io = require('socket.io-client')var socket = io.connect('@987654322 @', {reconnect: true});
  • @Shrawan socket.io 和 socket.net 是两个不同的框架。对于 Node.js,您使用 socket.net

标签: node.js sockets


【解决方案1】:

我的解决方案:

var parentHOST = '192.168.2.66';
var parentPORT = 9735;

var net = require('net');
var S = require('string');
var parentClient = new net.Socket();
var parentActive = false;

var startParentClient = function () {
    parentClient = new net.Socket();
    parentActive = false;

    parentClient.connect(parentPORT, parentHOST, function() {
      console.log('Connected ' + cluster.worker.id + ' to parent server: ' + parentHOST + ':' + parentPORT);
      parentActive = true;
    });

    parentClient.on('error', function() {
      parentActive = false;
      console.log('Parent connection error');
    });

    parentClient.on('close', function() {
      parentActive = false;
      console.log('parent connection closed');
      setTimeout(startParentClient(), 4000);
    });
  }

如果需要连接:

  if (!S(parentHOST).isEmpty() && !S(parentPORT).isEmpty()) {
    startParentClient();
  }

【讨论】:

  • 只是:setTimeout(startParentClient(), 4000);
【解决方案2】:

我使用以下代码实现与node.js的重新连接。我不是 Javascript 专家,所以我想它可以改进,但它对我来说仍然很好。 我希望这会有所帮助。 最好的。

//----------------------------------------------------------------//
// SocketClient                                                   //
//----------------------------------------------------------------//
var net = require('net');

var SocketClient = function(host, port, data_handler, attempt)
{
    var node_client;
    var attempt_index = (attempt ? attempt : 1);

    this.m_node_client = new net.Socket();
    node_client = this.m_node_client;
    this.m_node_client.on('close', function()
    {
        var new_wrapper = new SocketClient(host, port, data_handler, attempt_index + 1);

        node_client.destroy();
        new_wrapper.start();
    });
    this.m_node_client.on('data', data_handler);
    this.m_node_client.on('error', function(data)
    {
        console.log("Error");
    });
    this.start = function()
    {
        this.m_node_client.connect(port, host, function()
        {
            console.log('Connected ' + attempt_index);
        });
    };
};

//----------------------------------------------------------------//
// Test                                                           //
//----------------------------------------------------------------//
var test_handler = function(data)
{
    console.log('TestHandler[' + data + ']');
};
var wrapper = new SocketClient('127.0.0.1', 4000, test_handler);

wrapper.start();

【讨论】:

    【解决方案3】:

    问题在于您设置连接时回调的位置。

    The doc of socket.connect() 说:

    connectListener ... 将添加一次作为“连接”事件的侦听器。

    通过在 socket.connect() 调用中设置它,每次尝试重新连接时,都会向该套接字附加一个调用 startSequence() 的侦听器(一次性侦听器)。在重新连接成功之前不会触发这些侦听器,因此您可以在一次连接上同时触发所有侦听器。

    一种可能的解决方案是将连接侦听器与 socket.connect() 调用分开。

    client.on('connect', function() {
        pmsStartSequence();
    });
    
    client.on('close', function(e) {
        client.setTimeout(10000, function() {
            client.connect(HOST_PORT, HOST_IP);
        })
    });
    
    client.connect(HOST_PORT, HOST_IP);
    

    【讨论】:

    • 这是一个关键点,因为不仅close甚至不移除监听器,调用.end(),甚至.destroy()也不会移除监听器。所以当你再次连接时,你会得到重复的事件。 ebs 的解决方案很优雅,但是你可以在 close 事件上调用 .removeAllListeners() ,然后在重新连接时重新添加它们。
    • 是的,功能分离会解决问题
    【解决方案4】:

    受其他解决方案的启发,我写了这个,它已经过测试,它有效! 它将继续每 5 秒尝试一次,直到建立连接,如果它也失去连接也可以工作。

    /* Client connection */
    /* --------------------------------------------------------------------------------- */
    
    const client = new net.Socket()
    var intervalConnect = false;
    
    function connect() {
        client.connect({
            port: 1338,
            host: '127.0.0.1'
        })
    }
    
    function launchIntervalConnect() {
        if(false != intervalConnect) return
        intervalConnect = setInterval(connect, 5000)
    }
    
    function clearIntervalConnect() {
        if(false == intervalConnect) return
        clearInterval(intervalConnect)
        intervalConnect = false
    }
    
    client.on('connect', () => {
        clearIntervalConnect()
        logger('connected to server', 'TCP')
        client.write('CLIENT connected');
    })
    
    client.on('error', (err) => {
        logger(err.code, 'TCP ERROR')
        launchIntervalConnect()
    })
    client.on('close', launchIntervalConnect)
    client.on('end', launchIntervalConnect)
    
    connect()
    

    【讨论】:

    • 我注意到如果我想调用client.destroy(),它会再次触发launchIntervalConnect并防止连接被破坏。知道如何解决吗?谢谢。
    • 想出一个变通办法:client.removeAllListeners(),然后是client.destroy()
    • 谢谢,这对我有很大帮助
    • 这很完美!老实说,这应该是最佳答案。优雅地处理它。
    • 你可以把这行if(false != intervalConnect) return改成if(intervalConnect) return
    【解决方案5】:

    正如 cmets 中多次提到的,在尝试将客户端重新连接到服务器之前,您需要使用 .removeAllListeners(),以避免在同一事件上有多个侦听器。

    下面的代码应该可以解决问题

    请注意,我尝试在 closeend 事件之后重新连接客户端,因为这两个事件在关闭连接后可以以不同的顺序触发

    const net = require("net")
    
    let client = new net.Socket()
    
    function connect() {
        console.log("new client")
        client.connect(
            1337,
            "127.0.0.1",
            () => {
                console.log("Connected")
                client.write("Hello, server! Love, Client.")
            }
        )
    
        client.on("data", data => {
            console.log("Received: " + data)
        })
    
        client.on("close", () => {
            console.log("Connection closed")
            reconnect()
        })
    
        client.on("end", () => {
            console.log("Connection ended")
            reconnect()
        })
    
        client.on("error", console.error)
    }
    
    // function that reconnect the client to the server
    reconnect = () => {
        setTimeout(() => {
            client.removeAllListeners() // the important line that enables you to reopen a connection
            connect()
        }, 1000)
    }
    
    connect()
    

    【讨论】:

    • 这个答案简洁明了,但有时 end 和 close 会因为一次断开连接而被背靠背调用。下面受此启发的其他一些答案似乎效果更好
    【解决方案6】:

    我已经尝试通过使用这个来重新使用相同的套接字连接:

    const s = net.createConnection({port});
    
    s.once('end', () => {
        s.connect({port}, () => {
    
        });
    });
    

    从服务器端的角度来看,这不起作用。如果客户端连接关闭,最好创建一个新连接:

    const s = net.createConnection({port});
    
    s.once('end', () => {
        // create a new connection here
        s = net.createConnection(...);
    });
    

    悲伤但真实的 lulz。

    【讨论】:

      【解决方案7】:

      关注this

      //
      // Simple example of using net.Socket but here we capture the
      // right events and attempt to re-establish the connection when
      // is is closed either because of an error establishing a
      // connection or when the server closes the connection.
      //
      
      // Requires
      const net = require('net');
      
      // Create socket
      const port = 5555;
      const host = '127.0.0.1';
      const timeout = 1000;
      let retrying = false;
      
      // Functions to handle socket events
      function makeConnection () {
          socket.connect(port, host);
      }
      function connectEventHandler() {
          console.log('connected');
          retrying = false;
      }
      function dataEventHandler() {
          console.log('data');
      }
      function endEventHandler() {
          // console.log('end');
      }
      function timeoutEventHandler() {
          // console.log('timeout');
      }
      function drainEventHandler() {
          // console.log('drain');
      }
      function errorEventHandler() {
          // console.log('error');
      }
      function closeEventHandler () {
          // console.log('close');
          if (!retrying) {
              retrying = true;
              console.log('Reconnecting...');
          }
          setTimeout(makeConnection, timeout);
      }
      
      // Create socket and bind callbacks
      let socket = new net.Socket();
      socket.on('connect', connectEventHandler);
      socket.on('data',    dataEventHandler);
      socket.on('end',     endEventHandler);
      socket.on('timeout', timeoutEventHandler);
      socket.on('drain',   drainEventHandler);
      socket.on('error',   errorEventHandler);
      socket.on('close',   closeEventHandler);
      
      // Connect
      console.log('Connecting to ' + host + ':' + port + '...');
      makeConnection();
      

      【讨论】:

        【解决方案8】:
        function createServer() {
          const client = new net.Socket();
        
          client.connect(HOST_PORT, HOST_IP, function() {
            console.log("Connected");
            state = 1 - state;
            client.write(state.toString());
          });
        
          client.on("data", function(data) {
            console.log("Received: " + data);
            //client.destroy(); // kill client after server's response
          });
        
          client.on("close", function() {
            console.log("Connection closed");
            //client.connect()
            setTimeout(createServer, 2000);
          });
        }
        
        createServer();
        

        【讨论】:

        • 请添加一些文字说明您的解决方案的工作原理
        猜你喜欢
        • 2021-05-01
        • 2020-11-21
        • 1970-01-01
        • 1970-01-01
        • 2021-06-26
        • 2020-09-21
        • 2023-03-07
        • 2012-07-06
        • 1970-01-01
        相关资源
        最近更新 更多