深入分析 portfinder

3,480 阅读2分钟

遇到的问题:

有没有在做公众号开发的时候,本地需要启动80端口,但是你用脚手架端口号最低从1024启动的?如果你也遇到过这个问题。下面这篇文章将带你解决这个问题。


站在巨人的肩膀上

记得在最开始使用vue脚手架的时候,陪位文件都在build文件夹中,我们在做本地开发的时候,有时候启动两个服务的时候就出现:throw new ERR_SERVER_ALREADY_LISTEN(); 错误。 这个错误很好理解。意思是说:你的端口号已经本占用了。

所以当时做开发的时候,本次限制,本地只能启动一个服务。在做多个业务开发的时候。会比较繁琐。

好在,新版的脚手架中已经改进了许多,不经配置文件做成零配置的了,还允许我们本地启动多个服务,如果发现端口被使用了,端口号+1,帮助你启动服务。

感觉大佬们,给我们把坑填平,让我们有一个更快乐的开发环境。好了废话不多说了还是将原理。


探索思路


import { getPort } from 'portfinder';
getPort(
    {
      port: config.devServer!.port,
    },
    (err, port) => {
      if (err) {
        console.log(err);
        return;
      }

      logServerInfo(port);
      runDevServer(port, config);
}


在挖掘源码的时候,我们会发现这个库。看代码,大概的意思是,我们调用一个函数,可以返回我们一个没有被占用的函数。那么他的底层原理是怎么实现的呢?


去github上搜索一下,快速链接点击这里: portfinder


原理发现

使用net去跟一个个端口好建立链接,如果发现有一个端口号可以使用,会把能够使用的端口号返回给你。下面实现了简易版的代码:


const net = require('net');

var server = net.createServer(() => { })

function nextPort(port) { // 端口号 + 1
  return port + 1;
};

function getport(port, callback) {
  function onListen(data) {
    // 链接成功,关闭端口,清楚注销事件
    callback(null, port);
    server.removeListener('error', onError);
    server.close(); 
  }

  function onError(err) {
    // 链接失败端口号+1
    getport(nextPort(port))
  }
  server.once('error', onError); // 端口没有链接成功时触发
  server.once('listening', onListen); // 端口链接成功时触发
  server.listen(port); //
}

getport(1024, (err,port) => {
  console.log(port);
})


经过测试,发现我们这个代码的端口号是可以从80开始启动的。但是我们使用脚手架第三方包里面,为什么每次就算设置了80端口,发现启动的时候,也是从1024端口开始的呢?


结论

经过断电调试发现,从80端口开始,到1023端口都进入了onError函数,获取错误信息:

Error: listen EACCES: permission denied 127.0.0.1:80

重点:permission denied ,😯,原来是权限不允许,立马使用sudo npm run dev;发现启动果然是从80端口了。


总结: 当你不是管理员权限时,你是不能使用1024以下的端口的。


分析完毕,收工~