2013-09-18 2 views
21

У меня есть сервер HTTP, созданный с помощью:Force закрыть все соединения в Node.js HTTP сервер

var server = http.createServer()

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

server.close()

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

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

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

+1

возможный дубликат (HTTP: // StackOverflow. com/questions/14626636/how-do-i-shutdown-a-node-js-https-server-немедленно) – WiredPrairie

ответ

32

Вы должны

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

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

+4

+1, http://stackoverflow.com/a/14636625/303270 – fardjad

8

Для справки для других, которые спотыкаются по этому вопросу, библиотека https://github.com/isaacs/server-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); 
    }); 
} 

это как говорит Эге Özcan, просто собирать гнезда на событие подключения, и при закрытии сервера, уничтожить их.

1

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

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

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

Я переписан оригинальные ответы, используя современные JS: [? Как мне выключить Node.js HTTP (S) сервер немедленно]

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); 
Смежные вопросы