【问题标题】:Force close all connections in a node.js http server强制关闭 node.js http 服务器中的所有连接
【发布时间】:2013-09-23 08:35:22
【问题描述】:

我创建了一个 http 服务器:

var server = http.createServer()

我想关闭服务器。大概我会通过调用来做到这一点:

server.close()

但是,这只会阻止服务器接收任何新的 http 连接。它不会关闭任何仍然打开的。 http.close() 接受回调,直到所有打开的连接实际断开后才会执行该回调。有没有办法强制关闭一切?

对我来说,问题的根源在于我有 Mocha 测试,它们在设置中启动 http 服务器 (beforeEach()),然后在拆卸时将其关闭 (afterEach())。但是由于仅仅调用server.close() 不会完全关闭,后续的http.createServer() 通常会导致EADDRINUSE 错误。等待close() 完成也不是一种选择,因为打开的连接可能需要很长时间才能超时。

我需要一些方法来强制关闭连接。我可以在客户端执行此操作,但会强制关闭所有测试连接,但我宁愿在服务器端执行此操作,即只告诉 http 服务器硬关闭所有套接字。

【问题讨论】:

标签: node.js http


【解决方案1】:

你需要

  1. 订阅服务器的connection 事件并将打开的套接字添加到数组中
  2. 通过订阅 close 事件并从阵列中删除关闭的套接字来跟踪打开的套接字
  3. 当您需要终止服务器时,在所有剩余打开的套接字上调用 destroy

您还可以在子进程中运行服务器并在需要时退出该进程。

【讨论】:

    【解决方案2】:

    供偶然发现此问题的其他人参考,https://github.com/isaacs/server-destroy 库提供了destroy() 服务器的简单方法(使用 Ege 描述的方法)。

    【讨论】:

    • 好像不再维护了
    • 19行代码需要多少维护?
    • @MaMa 超出您的预期。例如。该代码不适用于 HTTPS 服务器,不能很好地与 Promise 配合使用,并且不能干净地关闭连接。世界在向前发展——如今npmjs.com/package/stoppable 是一个更好的选择。
    • 这个方向的另一个项目是http-terminator:github.com/gajus/http-terminator
    【解决方案3】:

    我通常使用类似这样的东西:

    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);
        });
    }
    

    就像 Ege Özcan 所说,只需在连接事件上收集套接字,然后在关闭服务器时销毁它们。

    【讨论】:

      【解决方案4】:

      我已经使用现代 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);
      

      【讨论】:

        【解决方案5】:

        我的方法来自this one,它基本上做到了@Ege Özcan 所说的。

        唯一的补充是我设置了关闭服务器的路由,因为节点没有从我的终端('SIGTERM''SIGINT')获得信号。

        嗯,节点在执行node whatever.js 时从我的终端获取信号,但是当将该任务委托给脚本时(如 package.json 中的 'start' 脚本 --> npm start),它未能关闭Ctrl+C,所以这种方法对我有用。

        请注意,我在 Cygwin 下,对我来说,在此之前杀死服务器意味着关闭终端并重新打开它。

        另请注意,我使用 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();
          }
        };
        

        【讨论】:

          猜你喜欢
          • 2013-10-21
          • 2011-07-12
          • 2014-04-01
          • 2012-03-07
          • 1970-01-01
          • 1970-01-01
          • 2012-10-12
          • 2015-06-29
          相关资源
          最近更新 更多