简体   繁体   English

强制关闭 node.js http 服务器中的所有连接

[英]Force close all connections in a node.js http server

I have an http server created using:我有一个 http 服务器创建使用:

var server = http.createServer()

I want to shut down the server.我想关闭服务器。 Presumably I'd do this by calling:大概我会通过调用来做到这一点:

server.close()

However, this only prevents the server from receiving any new http connections.但是,这只会阻止服务器接收任何新的 http 连接。 It does not close any that are still open.它不会关闭任何仍然打开的。 http.close() takes a callback, and that callback does not get executed until all open connections have actually disconnected. http.close()接受一个回调,并且在所有打开的连接实际断开之前不会执行该回调。 Is there a way to force close everything?有没有办法强制关闭一切?

The root of the problem for me is that I have Mocha tests that start up an http server in their setup ( beforeEach() ) and then shut it down in their teardown ( afterEach() ).对我来说,问题的根源是我有 Mocha 测试,在他们的设置( beforeEach() )中启动一个 http 服务器,然后在他们的拆卸( afterEach() )中关闭它。 But since just calling server.close() won't fully shut things down, the subsequent http.createServer() often results in an EADDRINUSE error.但由于仅调用server.close()不会完全关闭,后续的http.createServer()通常会导致EADDRINUSE错误。 Waiting for close() to finish also isn't an option, since open connections might take a really long time to time out.等待close()完成也不是一种选择,因为打开的连接可能需要很长时间才能超时。

I need some way to force-close connections.我需要一些方法来强制关闭连接。 I'm able to do this client-side, but forcing all of my test connections to close, but I'd rather do it server-side, ie to just tell the http server to hard-close all sockets.我可以在客户端执行此操作,但会强制关闭所有测试连接,但我宁愿在服务器端执行此操作,即只告诉 http 服务器硬关闭所有 sockets。

You need to 你需要

  1. subscribe to the connection event of the server and add opened sockets to an array 订阅服务器的connection事件并将打开的套接字添加到数组
  2. keep track of the open sockets by subscribing to their close event and removing the closed ones from your array 通过订阅他们的close事件并从阵列中删除已关闭的事件来跟踪打开的套接字
  3. call destroy on all of the remaining open sockets when you need to terminate the server 当您需要终止服务器时,在所有剩余的打开套接字上调用destroy

You also have the chance to run the server in a child process and exit that process when you need. 您还有机会在子进程中运行服务器并在需要时退出该进程。

对于那些偶然发现这个问题的人来说, https://github.com/isaacs/server-destroy库提供了一种简单的方法来destroy()服务器(使用Ege描述的方法)。

I usually use something similar to this: 我通常使用类似的东西:

var express = require('express');
var server = express();

/* a dummy route */
server.get('/', function (req, res) {
    res.send('Hello World!');
});

/* handle SIGTERM and SIGINT (ctrl-c) nicely */
process.once('SIGTERM', end);
process.once('SIGINT', end);


var listener = server.listen(8000, function(err) {
    if (err) throw err;

    var host = listener.address().address;
    var port = listener.address().port;

    console.log('Server listening at http://%s:%s', host, port);
});


var lastSocketKey = 0;
var socketMap = {};
listener.on('connection', function(socket) {
    /* generate a new, unique socket-key */
    var socketKey = ++lastSocketKey;
    /* add socket when it is connected */
    socketMap[socketKey] = socket;
    socket.on('close', function() {
        /* remove socket when it is closed */
        delete socketMap[socketKey];
    });
});

function end() {
    /* loop through all sockets and destroy them */
    Object.keys(socketMap).forEach(function(socketKey){
        socketMap[socketKey].destroy();
    });

    /* after all the sockets are destroyed, we may close the server! */
    listener.close(function(err){
        if(err) throw err();

        console.log('Server stopped');
        /* exit gracefully */
        process.exit(0);
    });
}

it's like Ege Özcan says, simply collect the sockets on the connection event, and when closing the server, destroy them. 就像EgeÖzcan所说,只需在连接事件上收集套接字,并在关闭服务器时将其销毁。

I've rewriten original answers using modern JS: 我用现代JS重写了原始答案:

const server1 = http.createServer(/*....*/);
const server1Sockets = new Set();

server1.on("connection", socket => {
    server1Sockets.add(socket);
    socket.on("close", () => {
        server1Sockets.delete(socket);
    });
});

function destroySockets(sockets) {
    for (const socket of sockets.values()) {
        socket.destroy();
    }
}

destroySockets(server1Sockets);

My approach comes from this one and it basically does what @Ege Özcan said. 我的方法来自这个 ,它基本上是@EgeÖzcan所说的。

The only addition is that I set a route to switch off my server because node wasn't getting the signals from my terminal ( 'SIGTERM' and 'SIGINT' ). 唯一的补充是我设置了一个关闭我的服务器的路由,因为节点没有从我的终端获取信号( 'SIGTERM''SIGINT' )。

Well, node was getting the signals from my terminal when doing node whatever.js but when delegating that task to a script (like the 'start' script in package.json --> npm start ) it failed to be switched off by Ctrl+C , so this approach worked for me. 好吧,节点在执行node whatever.js时从终端获取信号,但是当将该任务委托给脚本时(如package.json中的'start'脚本 - > npm start ),它无法通过Ctrl+C关闭Ctrl+C ,所以这种方法对我有用。

Please note I am under Cygwin and for me killing a server before this meant to close the terminal and reopen it again. 请注意我在Cygwin之下并且在此之前杀死服务器意味着关闭终端并再次重新打开它。

Also note that I am using express for the routing stuff. 另请注意,我使用express表示路由。

var http=require('http');
var express= require('express');

var app= express();

app.get('/', function (req, res) {
    res.send('I am alive but if you want to kill me just go to <a href="/exit">/exit</a>');
});

app.get('/exit', killserver);

var server =http.createServer(app).listen(3000, function(){
  console.log('Express server listening on port 3000');
  /*console.log(process);*/
});


// Maintain a hash of all connected sockets
var sockets = {}, nextSocketId = 0;
server.on('connection', function (socket) {
  // Add a newly connected socket
  var socketId = nextSocketId++;
  sockets[socketId] = socket;
  console.log('socket', socketId, 'opened');

  // Remove the socket when it closes
  socket.on('close', function () {
    console.log('socket', socketId, 'closed');
    delete sockets[socketId];
  });

  // Extend socket lifetime for demo purposes
  socket.setTimeout(4000);
});


// close the server and destroy all the open sockets
function killserver() {
    console.log("U killed me but I'll take my revenge soon!!");
  // Close the server
  server.close(function () { console.log('Server closed!'); });
  // Destroy all open sockets
  for (var socketId in sockets) {
    console.log('socket', socketId, 'destroyed');
    sockets[socketId].destroy();
  }
};

There is now a closeAllConnections() method in v18.2.0 v18.2.0 现在有一个closeAllConnections()方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM