如何找到一个可用端口?
很多场景中,我们确实需要找一个空闲端口,比如启动一个子进程监听指定端口,然后通过这个端口与之通信
然后实现方式就有很多了:
VSCode的实现
比如VSCode,就是逐个连接,如果某个端口连接失败,并且错误不是ECONNREFUSED的话,那么就说明这个端口可用。
1 | function doFindFreePort(startPort: number, giveUpAfter: number, clb: (port: number) => void): void { |
这种方式完全混淆了“端口可以被监听”和“端口不能连接”这两个语义,虽然现在Linux上述代码能够正常工作,但是保不准哪天新添加一个类似ECONNREFUSED这样的错误码呢。
vscode-mono-debug的实现
然后继续找,发现vscode-mono-debug的实现:通过不指定端口的方式listen,让操作系统分配端口:
1 | public static int FindFreePort(int fallback) |
这种方式好了一点,但是比人调用这个函数是为了拿到端口去监听,而这个函数并不会保证这个端口不被别人占用,所以这个实现还是有一点问题。
最终解决方案
目前来看,操作系统内核(至少Linux)没有提供分配并预留端口的机制,所以得到空闲端口(或者叫可用端口)是不现实的。
目前,正确的做法就是:把取端口这件事情交给使用端口的单位。
比如,开头提到的“启动一个子进程监听指定端口,然后通过这个端口与之通信”,那就应该子进程通过不指定端口listen的方式,让操作系统分配端口;并将这个端口告诉父进程(比如通过stdout)。