nodejs中如何解除已绑定的端口


我有nodejs进程A和nodejs进程B。进程A在9000端口开了一个http server。进程B不断尝试绑定9000端口,并且由于端口已被占用而失败。这很正常。

现在进程A想要释放绑定的9000端口以使得进程B可以绑定。可是进程A不能退出。该如何做到呢?

补充

@Larvata 感谢你,你的代码是能够释放原端口的。我发现是我错误的描述了我的问题,补充如下:

我在windows上使用nodeJS启动一个http服务A。为了防止它挂掉,我启动了一个后备的http服务B,服务B会不断的尝试绑定同一个端口。如果http服务A因为某种原因退出了进程,那么服务B就会拿到那个端口的控制权,以替代http服务A。这个过程我可以通过代码完成。

然后我尝试将这个手动过程写入代码。代码会不断尝试绑定9000端口,绑定成功则提供http服务,并且开一新的进程,启动同一套代码:不断尝试绑定9000端口,绑定成功则代替前一个服务,并且开一个新的进程……

也就是进程A会开启进程B作为备胎,当进程A挂掉以后进程B会转正,并且开启进程C作为备胎……

由于开启的备胎显然不能随主进程挂掉而一起挂掉,所以有两种开启方法:
1. 通过windows的"start node xxx.js"命令启动
2. 通过cp.spawn的detached模式启动

备胎启动很顺利,但是遇到的问题是,进程A挂掉的时候,并没有将9000端口给释放,所以进程B一直无法绑定9000端口。端口只有当进程B也挂掉的时候才会被释放。但是我觉得这是说不通的,端口9000应该跟进程A一起释放才对,这种情况更像是一种port leak。

因为实际中无法决定进程A是怎么挂掉的,所以进程A不能主动关闭端口,所以我之前的问题归纳出现了问题。。。

附可执行代码(windows only)


 var express = require('express');
var http    = require('http');
var app = express();
var cp = require('child_process');

var server = http.createServer(app);
server.setTimeout(1000);

server.on('error', function(){
    console.log("Error:", arguments);
    setTimeout(tryToConnect, 3000);
});


server.on('listening', function()
{
    console.log("Listening");
     // var child = cp.spawn('node', ['donoting.js'], {
     //     detached: true,
     //     stdio: ['ignore', 'ignore', 'ignore']
     // });
     // child.unref();
    cp.exec('start node listen.js');
});

var tryToConnect = function()
{
    var port = 9000;
    console.log("Trying to connect to port", 9000);
    server.listen(9000);
};

tryToConnect();

代码应该达到的效果,应该是启动另一个窗口,然后当你把第一个关掉以后,新窗口中启动的程序取代关掉的程序。

进程 node.js

黑叔叔的怪胡子 10 years, 4 months ago

这里标记一下,我也想看看其他人的答案

如果是本机访问的话,我觉得没什么办法的,必定要先kill A再重新部署一番

如果是外机访问的话,倒是可以尝试一下用Ngnix或Apache做一下端口映射

shingle answered 10 years, 4 months ago

大致写了个demo
访问 http://127.0.0.1:8001/change 之后 会释放8001 并且重新绑定8002端口
这个需要用chrome测试 ie有10-20秒的延迟 不清楚具体原因 可能与keepalive有关


 http = require 'http'

openedSockets=[]
isClosing=false

onServerClose=()->
    console.log 'Server port released'
    isClosing=false
    server.listen 8002, '127.0.0.1'
    console.log 'Server running at http://127.0.0.1:8002/'

connListener=(req, res)->
    res.writeHead 200, {'Content-Type': 'text/plain'}
    res.end 'Hello World\n'

    if req.url is '/change'
        console.log "try closing"
        isClosing=true
        server.close onServerClose

        for socket in openedSockets
            socket.end ()->
                socket.destroy


server = http.createServer connListener

server.on 'connection',(socket)->
    openedSockets.push socket

server.listen 8001, '127.0.0.1'
console.log 'Server running at http://127.0.0.1:8001/'

凤蝶纹D死枪 answered 10 years, 4 months ago

Your Answer