【问题标题】:Node.JS net module handling unexpected connection lossNode.JS 网络模块处理意外的连接丢失
【发布时间】:2016-01-11 14:35:55
【问题描述】:

我无法弄清楚我遇到的一个问题。 我在我的 Node.JS 服务器上使用 Net 模块,用于监听客户端连接。

客户端确实正确连接到服务器,并且连接仍然可用于读取/写入数据。到现在为止还挺好。但是当客户端意外断开连接时(编辑。当互联网在客户端断开时)我想触发事件服务器端。

在 socket.io 中,它会通过 'disconnect' 事件来完成,但对于 Net 模块,这个事件似乎不存在。怎么可能?

我在 Google/StackOverflow 和 Net 文档 (https://nodejs.org/api/net.html) 上进行了搜索,但找不到任何有用的东西。如果我做错了什么,我很抱歉。

这是我得到的代码 sn-p:

var net = require('net');

var server = net.createServer(function(connection) {
    console.log('client connected');
    connection.wildcard = false;//Connection must be initialised with a configuration stored in the database
    connection.bidirectional = true;//When piped this connection will be configured as bidirectional

    connection.setKeepAlive(true, 500);
    connection.setTimeout(3000);

    connection.on('close', function (){
        console.log('Socket is closed');
     });

    connection.on('error', function (err) {
        console.log('An error happened in connection' + err.stack);
    });
    connection.on('end', function () {
        console.log('Socket did disconnect');
    });
    connection.on('timeout', function () {
        console.log('Socket did timeout');
        connection.end();
    });
    connection.on('data', function (data) {
        //Handling incoming data
    });

});

serverUmrs.listen(40000, function () {
    console.log('server is listening');
});

当我断开客户端(通过拔出 UTP 电缆)时,所有事件(关闭、结束、错误、超时)都不会触发。

提前致谢!

编辑: 我确实在上面的代码中添加了一个超时事件,但唯一发生的事情是,每次客户端再次连接时,套接字都会在 3 秒后超时。 KeepAlive 还不足以使套接字不空闲吗?如何在没有太多开销的情况下使套接字不空闲。有可能同时存在超过 10,000 个连接,只要它们连接(即响应 keepalive 消息)就必须保持活动状态。

【问题讨论】:

  • 拔出UTP线后,客户端3秒后是否再次连接?

标签: node.js sockets


【解决方案1】:

更新

我认为KeepAlivethe Idle state of socket 无关,有点。

这是我的测试,我在您的示例中删除了以下代码。

//connection.setKeepAlive(true, 500);

然后用一个客户端连接到它 var nc localhost 40000 来测试这个服务器。如果在3 秒后没有消息发送到服务器,则服务器记录如下

Socket did timeout
Socket did disconnect
Socket is closed

timeout 事件在没有KeepAlive 设置的情况下触发。

做进一步调查,参考Node.jscode

function onread(nread, buffer) {
  //...
  self._unrefTimer();

我们知道timeout事件是由socket的onread()操作触发的。即,如果在3 秒后没有读取操作,则会发出timeout 事件。更准确地说,不仅onread,而且write成功都会调用_unrefTimer()

综上所述,当对socket进行写或读操作时,它是NOT空闲的。


其实close事件是用来检测客户端连接是否存活,这个SOquestion也有提到。

服务器关闭时发出。请注意,如果存在连接,则在所有连接结束之前不会发出此事件。

但是,在你的情况下

断开客户端(通过拔出 UTP 电缆)。

timeout 事件应该用于检测连接不活动。这只是为了通知套接字已经空闲。用户必须手动关闭连接。请参考这个question

【讨论】:

  • 谢谢,但我没有使用超时事件的功能。有关更多信息,请参阅我的问题帖子中的编辑和更改代码 sn-p。
  • @Sander,我的答案更新了,希望对你有帮助。
【解决方案2】:

在 TCP 连接中,当客户端向服务器发送 'FIN' 消息时触发结束事件。

如果客户端未发送“FIN”消息,则事件未触发。

例如,在你的情况下,

但是当客户端意外断开连接时(编辑。当互联网在客户端断开时)我想触发事件服务器端。

可能没有“FIN”消息,因为互联网已经消失。

所以你应该在不使用keepAlive的情况下处理这种超时情况。如果没有数据传入数据,则应结束销毁套接字。

编辑:我确实在上面的代码中添加了一个超时事件,但唯一的 发生的事情是套接字在 3 秒后超时 每次客户端再次连接时。 KeepAlive 还不够 使套接字不空闲?怎么可能不让socket 空闲没有太多开销。可能还有更多 超过 10,000 个连接同时必须保持活动状态 只要它们已连接(即响应 keepalive 消息)。

对于您的编辑,您的设备应在一段时间之间向服务器发送一些心跳消息。这样,服务器就知道该设备是活动的,并且不会触发超时事件,因为您获得了一些数据。如果没有心跳消息这种情况你无法处理这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    相关资源
    最近更新 更多