Подтвердить что ты не робот

Принудительное закрытие всех подключений на http-сервере node.js

У меня есть http-сервер, созданный с помощью:

var server = http.createServer()

Я хочу закрыть сервер. Предположительно, я сделал бы это, позвонив:

server.close()

Однако это только предотвращает получение сервером новых HTTP-соединений. Он не закрывает все, что еще открыто. http.close() выполняет обратный вызов, и этот обратный вызов не выполняется, пока все открытые соединения фактически не отключены. Есть ли способ заставить все закрыть?

Корень проблемы для меня заключается в том, что у меня есть тесты Mocha, которые запускают HTTP-сервер в их настройке (beforeEach()), а затем закрывают его в режиме teardown (afterEach()). Но так как просто вызов server.close() не будет полностью закрывать все, последующий http.createServer() часто приводит к ошибке EADDRINUSE. Ожидание close() для завершения также не является опцией, поскольку открытые соединения могут занимать очень много времени.

Мне нужен способ принудительно закрыть соединения. Я могу сделать это на стороне клиента, но заставляю все мои тестовые подключения закрываться, но я предпочел бы сделать это на стороне сервера, то есть просто сообщить http-серверу о том, чтобы закрыть все сокеты.

4b9b3361

Ответ 1

Вам нужно

  • подписаться на событие connection сервера и добавить открытые сокеты в массив
  • отслеживать открытые сокеты, подписываясь на их событие close и удаляя закрытые из вашего массива
  • вызывать destroy во всех остальных открытых сокетах, когда вам нужно завершить работу сервера

У вас также есть возможность запустить сервер в дочернем процессе и выйти из этого процесса, когда вам нужно.

Ответ 2

Для справки для других, которые спотыкаются по этому вопросу, библиотека https://github.com/isaacs/server-destroy обеспечивает простой способ destroy() сервера (используя подход, описанный Ege).

Ответ 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

Мой подход исходит от этого и в основном делает то, что сказал @Ege Özcan.

Единственное дополнение - установить маршрут для отключения моего сервера, потому что node не получал сигналы от моего терминала ('SIGTERM' и 'SIGINT').

Ну, node получал сигналы от моего терминала при выполнении node whatever.js, но при делегировании этой задачи на script (например, 'start' script в package.json → 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();
  }
};