如何检测 net.Socket 连接是否断开 - node.js

12

背景

我正在使用TCP/IP通过 net.Socket 与机器进行通信。

我已经成功地建立了连接并能够发送和接收缓冲区数据包,一切都很好。

问题

问题是,如果我手动从机器上断开互联网电缆,则我的 Node.js 连接不会触发 close 事件,而我无法知道是否发生了故障!

代码

let socket;

const start = async function ( config ) {

    await connecToBarrier( config )
        .then( () => console.log( "connected to barrrier" ) )
        .catch( err => {
            throw new Error( `Cannot connect to barrier: ${err}` );
        } );
};

const connecToBarrier = function ( connectOpts ) {
    return new Promise( ( resolve, reject ) => {
        //connectOpts is an object with 'port' and 'host'
        socket = net.createConnection( connectOpts, () => {
            //once I receive a 'hello world' from the machine, I can continue
            socket.once( "data", () => resolve() );
        } );

        socket.on( "connection", () => {
            console.log("onConnection says we have someone!");
        } );

        socket.on( "error", err => {
            console.log(`onError says: ${err}`);
            reject(err);
        } );

        socket.on( "timeout", () => {
            console.log("onTimeout says nothing");
            reject();
        } );

        socket.on( "end", () => {
            console.log("onEnd says nothing");
            reject();
        } );

        socket.on( "close", err => {
            console.log(`onClose says: ${err}`);
            reject(err);
        } );
    } );
};


start();

研究

@robertklep提到了setKeepAlive选项,但是根据在NodeJS中如何测试socket.setKeepAlive 它不起作用。更深入的研究表明,这高度依赖于您使用的操作系统,因为https://dev59.com/J3bZa4cB1Zd3GeqPGHYG#18678494所述。

换句话说,除非我愿意等待几分钟让我的心跳实际上做点什么,否则我看不到任何出路。

问题

如何检测连接是否断开?

2个回答

10

这是一篇有趣的阅读材料:https://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html

特别注意以下话语:

TCP 中,接收数据的行为完全是被动的;只读取数据的 socket 无法检测到断开的连接。

这正是你的情况:你的套接字正在等待新的数据到达,但却从未发生。一些 OS,尤其是 UNIX 类型的系统,如果网络接口崩溃了,可能会等待很长时间才开始无效化已经打开的连接。

该文章还提出了一个在 Node.js 上可能适用的解决方案:启用 TCP Keepalive。这将定期发送数据包给对等方以检查连接是否仍在工作。

要在您的套接字上启用此功能:

socket.setKeepalive(true, 5000);

收到最后一个数据包 5 秒之后,这将开始检查连接。更多信息请参见此处:https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay


1
如果连接在此期间中断会发生什么?哪个net.Socket甚至会被触发? - Flame_Phoenix
1
根据以上代码,从未触发任何事件! - Flame_Phoenix
2
看起来在Node.js中setKeepAlive不可靠 https://dev59.com/-3rZa4cB1Zd3GeqPzjXe ... 太好了,正是我需要的。尽管如此,感谢你的帮助!另外,很高兴再次见到你:D - Flame_Phoenix
1
这取决于您的操作系统设置,它在哪个时间点将考虑连接已断开。对于Linux而言,在停止发送保持活动并声明连接已断开之前,可能仍需要11分钟。但是您可以缩短这段时间:http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive.html setKeepAlive 的作用是缩短默认的“等待期”,在此之后内核开始发送保持活动数据包(在Linux上为2小时...)。 - robertklep

5

我曾经遇到过相同的问题。最终,我采用了以下方法进行修复:

const _connect = () => {
  const socket = new net.Socket();
    socket.connect(this.port, this.host);
    socket.setTimeout(10000);

    socket.on('timeout', () => {
        socket.destroy();
        _connect(); 
    });
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接