Node.js:当TCP连接关闭时,客户端不会终止。

5

我用Node.js构建了一个简单的TCP服务器和客户端。

现在,当客户端向服务器发送“exit”时,连接会成功关闭。服务器从其套接字列表中删除套接字,并向客户端发送“Bye bye!”。

客户端上的连接也关闭了,但应用程序仍在等待其他输入,因此它不会停止运行,我被迫输入CTRL+C。

我尝试在连接关闭后添加process.exit(),但它并没有起作用:

客户端代码:

var net = require('net'),
    config = require(__dirname + '/config.json'),
    connection = net.createConnection(config.port, config.host);

connection.setEncoding('utf8');

connection.on('connect', function () {
    console.log('Connected');
});

connection.on('error', function (err) {
    console.error(err);
});

connection.on('data', function (data) {
    console.log('» ' + data);
});

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

process.stdin.on('data', function (data) {

    if ((new String(data)).toLowerCase() === 'exit') {
        connection.end();
        process.exit();
    }
    else {
        connection.write(data);
    }

});

process.stdin.resume();

服务器代码:

var server = require('net').createServer(),
    config = require(__dirname + '/config.json'),
    sockets = [];

server.on('connection', function (socket) {
    socket.setEncoding('UTF-8');

    socket.on('data', function (data) {

        console.log('Received data: ' + data);

        if (data.trim().toLowerCase() === 'exit') {
            socket.write("Bye bye!\n");
            socket.end();
        }
        else {
            sockets.forEach(function (client) {
                if (client && client != socket) {
                    client.write(data);
                }
            });
        }

    });

    socket.on('close', function () {
        console.log('Connection closed');
        sockets.splice(sockets.indexOf(socket), 1);

        console.info('Sockets connected: ' + sockets.length);
    });

    sockets.push(socket);
});

server.on('listening', function () {
    console.log('Server listening');
});

server.on('close', function () {
    console.log('Server is now closed');
});

server.on('error', function (err) {
    console.log('error:', err);
});

server.listen(config.port);

编辑:

我添加了一个客户端连接的“关闭”事件处理程序。因此,服务器和客户端现在都会打印字符串“连接已关闭”。

5个回答

4

我认为您正在寻找这个:socket.unref()。

来自Node.js文档 (https://nodejs.org/api/net.html#net_socket_unref):

socket.unref()#

在套接字上调用unref将允许程序退出,如果这是事件系统中唯一活动的套接字。 如果套接字已经被取消引用,则再次调用unref将无效。


2
不久前,当我为node-cubrid模块改进测试套件时,遇到了同样的问题。在所有测试都通过后,nodeunit进程没有退出,因为node-cubrid在超时时使用connection.end()关闭客户端套接字,就像你所做的那样。
然后,我用connection.destroy()替换了connection.end(),这是一种更清洁的方式,可以确保套接字被真正关闭,而不会终止运行中的进程。我认为,这比上面建议的process.exit()更好。因此,在您的客户端代码上下文中,我会这样做:
process.stdin.on('data', function (data) {
    if ((new String(data)).toLowerCase() === 'exit') {
       connection.destroy();
    }
    else {
       connection.write(data);
    }
});

根据 Node.js 文档

socket.destroy()

确保在此套接字上不再发生更多的 I/O 活动。仅在出现错误(如解析错误等)时才需要。


1
我尝试使用connection.destroy()方法,但在我的应用程序中结果是相同的。它关闭连接,就像connection.end()一样。关键是在连接关闭后进程仍在运行,只有在connection.end()connection.destroy()之后调用process.exit()才能给我所需的行为。请阅读我的答案。您必须将process.exit()放在connection.on('close')事件处理程序中,以便在连接关闭(或销毁)后执行。在命令行上尝试我的代码。 - Francesco Casula
1
当您调用end()时,close事件不会立即触发。它会在套接字实际关闭后被调用,例如,在end()之后,服务器会发送bye(这是服务器的+1个数据包),或者在destroy()之后立即强制断开连接。一旦套接字关闭,在close事件处理程序中,没有必要使用process.exit(),因为这是进程将在您的示例中执行的最后一件事情。 - esengineer
1
不,你必须调用 process.exit() 指令,否则客户端不会关闭,你必须按下 CTRL+C 快捷键才能在 shell 上输入。这是问题所在,只有 process.exit() 指令可以修复我发布的代码中的这种行为。如果你找到了其他方法来解决我的应用程序中的这个特定行为,请发布出来。connection.destroy() 无法解决我的挂起行为。我已经尝试过了。 - Francesco Casula

0

在编程中,你必须只在最后一个事件处理程序中放置process.exit()指令。因此,在这种情况下,你必须将其放置在客户端连接的“关闭”事件处理程序中:

客户端:

connection.on('close', function() {
    console.log('Connection closed');
    process.exit();
});

0

我怀疑 if ((new String(data)).toLowerCase() === 'exit') 成功是因为 data 很可能有一个尾随的换行符(在您的服务器上,您在比较之前进行了trim(),但在客户端没有)。

如果这个问题解决了,你还有一个逻辑问题:当获取到“exit”时,你关闭连接而不将“exit”发送到服务器,所以寻找“exit”的服务器代码将永远不会执行。


(new String(data)).toLowerCase() 的运行非常完美,因为连接已经成功关闭,事实上服务器向客户端发送了“再见!”并打印了“连接已关闭\n已连接的套接字数:0”... 因此客户端已断开连接,服务器正在等待未来的连接,但客户端进程(而不是连接)仍然处于活动状态。 - Francesco Casula

0

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