本文翻译自 Python Getting A Free Port Number : A Multiprocess-safe Recipe
写本文的目的是介绍如何在 Python 中实现一个函数:get_free_port
返回一个未使用的端口号,并且这个函数支持在多线程和多进程环境中使用。
这也就意味着 get_free_port
可以在任何时候任意地方调用返回的端口号都能被绑定。
事实上,这个目标在逻辑上并不能实现,因为这个函数并不知道它返回的端口号是否已经被使用了,所以最佳的实践方式就是记住所有返回的端口号,每次调用都检查端口号是否已经输出过。
如果我们再增加一个函数用来释放端口就显得更符合逻辑了。
在 Python 中调用 socket.bind(('', 0))
会自动绑定一个端口号,所以我们可以借助这一特性来实现:
1 | import socket |
这个函数看上去能工作,但是还远远不够。采用这个方法只能让端口在非常短的时间内不被绑定,难以满足在竞态场景中使用。
由此不难看出,获得一个未被绑定的端口号不难,难的是如何把这个端口号安全正确地返回给调用者。鉴于此,我们需要找到一种机制可以首先保证这个未绑定的端口号不被肆意绑定:
1 | get a free port -> look at dictionary (and lock file) -> bind a free port -> write a dictionary (and lock file) -> release port -> return the port |
使用 lock file
能够保证即使端口号未绑定,在未拿到锁之前是不会被其他进程绑定的,在这里使用了。全部代码如下:
1 | # freeport.py |
测试如下:
1 | #freeport_test.py |