Python 检查套接字端口是否可用
情况: 我有一个应用程序,它有一个TCP服务器作为它的一部分(基于Python 检查套接字端口是否可用,python,sockets,tcp,Python,Sockets,Tcp,情况: 我有一个应用程序,它有一个TCP服务器作为它的一部分(基于socketserver),我想对它进行功能测试 我自己创建了一个测试mixin,我在每个测试用例中都使用它: class AppProcessManagingMixin: _used_tcp_ports = set() def start_my_app(self): port = self._take_tcp_port() prepare_config_with_given_tc
socketserver
),我想对它进行功能测试
我自己创建了一个测试mixin,我在每个测试用例中都使用它:
class AppProcessManagingMixin:
_used_tcp_ports = set()
def start_my_app(self):
port = self._take_tcp_port()
prepare_config_with_given_tcp_port(port)
# use prepared config by subprocess below
Popen([python_executable_path, my_app_name, ...).start()
def _take_tcp_port(self):
available_found = False
while not available_found:
port = random.randint(9000, 9999) # these ints are arbitrary here
available_found = port not in self._used_tcp_ports
self._used_tcp_ports.add(port)
return port
def stop_my_app(self):
so_something_that_Im_sure_will_stop_my_app_after_a_few_seconds()
每个测试用例setUp()
调用self.start\u my\u app()
,每个tearDown()
-self.stop\u my\u app()
,我可以依赖于停止我的应用。我需要我的应用程序的许多实例(并且不能在类范围的设置/拆卸中启动/停止应用程序),因为我的一些测试正在检查应用程序在以空工作目录开始的场景中是否工作良好(我只需要这些测试的“空”应用程序实例)
我对第二种方法有问题,\u take\u tcp\u port
。在我引入它之前,我经常会遇到关于已获取地址的问题(因为所有测试都尝试在同一端口上运行TCP服务器)。现在这种情况并不经常发生,但它还是发生了
我知道它依赖于系统,几秒钟后端口将再次可用,但这使自动化测试更加困难
问题:
如何检查TCP服务器是否有可用的地址(主机和端口)?我想在\u take\u tcp\u port
中检查它,以确保测试不会失败,因为应用实例的take端口有问题
我所做的研究:
我浏览了以下谷歌搜索的第一页:
- 检查端口是否打开
- 检查端口是否可用
- 发现可用端口
这需要是多平台的(至少是Windows、Linux、MacOS)。它必须至少在p3.3+中工作。如果“有一个lib”就足够了;) 您不需要手动扫描可用端口,操作系统会帮您完成。调用bind()时只需指定端口0,操作系统就会选择一个端口。这对于测试通常很有用——您可以使用端口0启动一个端点,让它询问系统它实际获得了什么端口(getsockaddr),然后使用该端口号启动第二个端点。这很有用,但是我如何在弹出的进程之外获得该端口?有些测试需要连接到此TCP服务器,并且为了尽可能接近模拟真实场景,我希望使用Popen运行此测试,可能使用shell=True,以隔离测试进程和应用程序进程(而不是在其他线程中的测试进程中调用其main()函数,或multiprocessing.process)。一个选项是通过Popen将命令行参数传递给程序,Popen指定一个文件名,程序一旦知道该文件名,就会将端口号写入该文件。或者甚至让你的启动器监听任何端口,并让它将该端口号传递给子端口,子端口将使用该端口号发回。这有点奇怪,但如果你不愿意在IPC中使用文件系统,它会起作用。这意味着,我需要在应用程序中实现一些东西,这些东西没有实际用途,只是为了测试而创建的。我认为这是不好的实践——我开始将应用逻辑和测试逻辑结合起来,这并不好。不过,我们可能会将存储使用过的配置(复制)的东西添加到工作区,以便可以检查应用程序的状态——然后,我们将使用这种方法。谢谢