单线程 单进程环境

def getPort():pscmd = "netstat -ntl |grep -v Active| grep -v Proto|awk '{print $4}'|awk -F: '{print $NF}'"procs = os.popen(pscmd).read()procarr = procs.split("\n")tt= random.randint(15000,20000)if tt not in procarr:return ttelse:return getPort()

多线程 多进程环境

写本文的目的是介绍如何在 Python 中实现一个函数:get_free_port 返回一个未使用的端口号,并且这个函数支持在多线程和多进程环境中使用。

这也就意味着 get_free_port 可以在任何时候任意地方调用返回的端口号都能被绑定。

事实上,这个目标在逻辑上并不能实现,因为这个函数并不知道它返回的端口号是否已经被使用了,所以最佳的实践方式就是记住所有返回的端口号,每次调用都检查端口号是否已经输出过。

如果我们再增加一个函数用来释放端口就显得更符合逻辑了。

在 Python 中调用 socket.bind(('', 0)) 会自动绑定一个端口号,所以我们可以借助这一特性来实现:

import socket def get_free_port():  sock = socket.socket()sock.bind(('', 0))ip, port = sock.getnameinfo()sock.close()return port

这个函数看上去能工作,但是还远远不够。采用这个方法只能让端口在非常短的时间内不被绑定,难以满足在竞态场景中使用。

由此不难看出,获得一个未被绑定的端口号不难,难的是如何把这个端口号安全正确地返回给调用者。鉴于此,我们需要找到一种机制可以首先保证这个未绑定的端口号不被肆意绑定:

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 能够保证即使端口号未绑定,在未拿到锁之前是不会被其他进程绑定的,在这里使用了。全部代码如下:

# freeport.py
import fasteners
import threadingclass BindFreePort(object):def __init__(self, start, stop):self.port = Noneimport random, socketself.sock = socket.socket()while True:port = random.randint(start, stop)try:self.sock.bind(('', port))self.port = portbreakexcept Exception:continuedef release(self):assert self.port is not Noneself.sock.close()class FreePort(object):used_ports = set()def __init__(self, start=4000, stop=6000):self.lock = Noneself.bind = Noneself.port = Nonefrom fasteners.process_lock import InterProcessLockimport timewhile True:bind = BindFreePort(start, stop)if bind.port in self.used_ports:bind.release()continue'''Since we cannot be certain the user will bind the port 'immediately' (actually it is not possible usingthis flow. We must ensure that the port will not be reacquired even it is not bound to anything'''lock = InterProcessLock(path='/tmp/socialdna/port_{}_lock'.format(bind.port))success = lock.acquire(blocking=False)if success:self.lock = lockself.port = bind.portself.used_ports.add(bind.port)bind.release()breakbind.release()time.sleep(0.01)def release(self):assert self.lock is not Noneassert self.port is not Noneself.used_ports.remove(self.port)self.lock.release()

测试如下:

#freeport_test.py
from freeport import FreePortdef get_and_bind_freeport(*args):freeport = FreePort(start=4000, stop=4009)import timetime.sleep(1)return freeport.portclass FreePortClassTest(unittest.TestCase):def test_one_port(self):freeport = FreePort(start=4000, stop=4000)self.assertEqual(freeport.port, 4000)freeport.release()def test_many_ports(self):freeport = FreePort(start=4000, stop=4000)self.assertEqual(freeport.port, 4000)freeport.release()freeport = FreePort(start=4000, stop=4000)self.assertEqual(freeport.port, 4000)freeport.release()def test_many_ports_conflict(self):def get_port():freeport = FreePort(start=4000, stop=4000)return freeport.portdef run():self.assertEqual(get_port(), 4000)freeport = FreePort(start=4000, stop=4000)self.assertEqual(freeport.port, 4000)from multiprocessing import Processp = Process(target=run)p.start()p.join(0.1)self.assertTrue(p.is_alive(), 'the process should find it hard to acquire a free port')p.terminate()p.join()freeport.release()def test_multithread_race_condition(self):from multiprocessing.pool import ThreadPooljobs = 100def get_and_bind_freeport(*args):freeport = FreePort(start=4000, stop=4000 + jobs - 1)import timetime.sleep(1)freeport.release() # needed because thread will not turn back the file descriptorreturn freeport.portp = ThreadPool(jobs)ports = p.map(get_and_bind_freeport, range(jobs))self.assertEqual(len(ports), len(set(ports)))def test_multiprocess_race_condition(self):from multiprocessing.pool import Poolp = Pool(10)ports = p.map(get_and_bind_freeport, range(10))self.assertEqual(len(ports), len(set(ports)))

python3 得到一个可用未绑定端口相关推荐

  1. dotnet C# 获取一个可用的端口的方法

    本文来告诉大家如何可以获取一个可用的端口 使用如下代码可以返回一个可用的端口 public static int GetAvailablePort(IPAddress ip){TcpListener ...

  2. Windows——获取一个可用的端口

    作者:小 琛 欢迎转载,请标明出处 很多涉及到网络的业务场景下,需要给当前服务一个本机可用的端口,写死端口自然是不可取的,会像定时炸弹一样,因此最标准的解决方式就是:动态获取一个当前可以使用的端口号, ...

  3. 在网络通讯中,如何自己分配可用的端口号和获取自己的ip地址

    在编写一些程序时,为了程序可以在其他电脑上也可以使用,而不用手动去更改ip,或者碰到端口不可用的情况.在这里找到了一个好的方法,实际使用也没有问题!故此推荐给大家! 方案: 在构建网络时,使用: cl ...

  4. linux标准i o实例,9.3. 一个 I/O 端口例子

    ## 9.3. 一个 I/O 端口例子 我们用来展示一个设备驱动内的端口 I/O 的例子代码, 操作通用的数字 I/O 端口; 这样的端口在大部分计算机系统中找到. 一个数字 I/O 端口, 在它的大 ...

  5. Linux下安装Python3.6(可用)

    Centos下安装Python3.6(可用) 一.安装python3.6.1 1.安装依赖环境 #yum install readline-devel gcc make patch gdbm-deve ...

  6. Python3 反转一个单链表

    Python3 反转一个单链表 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1-&g ...

  7. QT5 C++编写B类IP地址计算第一个可用IP地址、最后一个可用IP地址、网络号、广播地址、子网数、主机数

    B类地址,斜线记法,192.168.60.1/24其中192.168.10.1是IP字符串strIP,24是子网掩码1的个数nSubnetMas,其中要求18<=nSubnetMas<=3 ...

  8. python3发起一个http请求

    python3发起一个http请求例子: import json from urllib import parse,requestdef getOpenRoomList():textmod = {'u ...

  9. 请用python3编写一个计算器的控制台程序_二、软件工程慕课第一章作业题——编写一个计算器...

    一.题目描述 请用Python3编写一个计算器的控制台程序,支持加减乘除.乘方.括号.小数点,运算符优先级为括号>乘方>乘除>加减,同级别运算按照从左向右的顺序计算. 二.输入描述 ...

最新文章

  1. Windows 1.0 to Windows 10
  2. javaweb学习总结(十四)——JSP原理
  3. python长代码_Python 的长代码文件怎么组织
  4. java上三角数组_二维数组的三角填充 两种java实现的方法
  5. DynamoRIO工作原理
  6. 详解Intellij IDEA中.properties文件中文显示乱码问题的解决
  7. CentOS 搭建简单svn服务器【转】
  8. ijkplayer 视频播放
  9. base | 文本处理方法(Ⅰ-2):正则表达式
  10. jmeter下TPS插件的安装
  11. 矩池云上安装及使用Milvus教程
  12. 【iOS】Unlock iPhone to Continue Xcode cannot launch demo1_greating on iPhone because the device is lo
  13. 百度深度学习图像识别决赛代码分享(OCR)
  14. mysql 二进制 查询_MySql如何插入和查询二进制数据_MySQL
  15. #pragma warning(disable 4786)
  16. 转贴:如何恢复Thunderbird里误删除的邮件?三种方法
  17. python生成曲线图
  18. 模板匹配人眼---OpenCV-Python开发指南(33)
  19. 数字1的ASCII值是多少
  20. Python(基础)输出与输入

热门文章

  1. Tungsten Fabric SDN — 软件架构
  2. Tungsten Fabric SDN — Overviw
  3. 5GS 协议栈 — N1 接口的协议栈(NAS)
  4. 架构师之路 — API 经济 — Swagger OpenAPI Specification
  5. 4G EPS 的架构模型
  6. Python 数据结构_队列
  7. Linux_自制系统服务启动脚本
  8. 文件上传漏洞及解决办法
  9. 0046算法笔记——【随机化算法】舍伍德随机化思想解决跳跃表问题
  10. Linux平台Oracle安装脚本