search

Home  >  Q&A  >  body text

node.js - 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();

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

PHPzPHPz2867 days ago812

reply all(2)I'll reply

  • 高洛峰

    高洛峰2017-04-17 11:24:02

    Written a rough demo
    After accessing http://127.0.0.1:8001/change, port 8001 will be released and port 8002 will be re-bound
    This needs to be tested with chrome. There is a 10-20 second delay in ie. I don’t know the specific reason. It may be related to 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/'
    

    reply
    0
  • 大家讲道理

    大家讲道理2017-04-17 11:24:02

    Mark it here, I also want to see other people’s answers

    If it is accessed locally, I think there is nothing you can do. You must kill A first and then redeploy it

    If it is accessed from an external machine, you can try using Ngnix or Apache to do port mapping

    reply
    0
  • Cancelreply