如何检测 net.Socket 连接是否终止 - node.js
How to detect if net.Socket connection dies - node.js
背景
我正在通过 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
选项,但是根据
How to test socket.setKeepAlive in NodeJS
没用。一项更深入的研究表明,这在很大程度上取决于您使用的操作系统,根据
所以换句话说,除非我愿意等待几分钟让我的心跳真正做一些事情,否则我看不出有什么办法。
问题
如何检测连接是否中断?
这里有一篇有趣的读物:https://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html
特别注意这句话:
It is important to note that the act of receiving data is completely passive in TCP; a socket that only reads cannot detect a dropped connection.
这正是您的情况:您的套接字正在等待新数据到达,但这种情况从未发生过。如果网络接口出现故障,一些 OS'es,尤其是 UNIX 类型的,可能会等待很长时间才能开始使打开的连接无效。
文章还提出了一个可能对Node.js有效的解决方案:启用TCP Keepalive。这将定期向对等方发送数据包以检查连接是否仍在工作。
要在您的套接字上启用此功能:
socket.setKeepalive(true, 5000);
这将在收到最后一个数据包 5 秒后开始检查连接。更多信息在这里:https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay
我遇到了同样的问题。我最终这样做是为了解决这个问题:
const _connect = () => {
const socket = new net.Socket();
socket.connect(this.port, this.host);
socket.setTimeout(10000);
socket.on('timeout', () => {
socket.destroy();
_connect();
});
}
背景
我正在通过 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
选项,但是根据
How to test socket.setKeepAlive in NodeJS
没用。一项更深入的研究表明,这在很大程度上取决于您使用的操作系统,根据
所以换句话说,除非我愿意等待几分钟让我的心跳真正做一些事情,否则我看不出有什么办法。
问题
如何检测连接是否中断?
这里有一篇有趣的读物:https://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html
特别注意这句话:
It is important to note that the act of receiving data is completely passive in TCP; a socket that only reads cannot detect a dropped connection.
这正是您的情况:您的套接字正在等待新数据到达,但这种情况从未发生过。如果网络接口出现故障,一些 OS'es,尤其是 UNIX 类型的,可能会等待很长时间才能开始使打开的连接无效。
文章还提出了一个可能对Node.js有效的解决方案:启用TCP Keepalive。这将定期向对等方发送数据包以检查连接是否仍在工作。
要在您的套接字上启用此功能:
socket.setKeepalive(true, 5000);
这将在收到最后一个数据包 5 秒后开始检查连接。更多信息在这里:https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay
我遇到了同样的问题。我最终这样做是为了解决这个问题:
const _connect = () => {
const socket = new net.Socket();
socket.connect(this.port, this.host);
socket.setTimeout(10000);
socket.on('timeout', () => {
socket.destroy();
_connect();
});
}