如何在自己的线程中释放绑定到Python监听器的端口

问题描述 投票:0回答:1

在下面的代码中,我试图释放一个正在由运行

multiprocessing.connection.Listener
的 python 线程监听的网络端口。尝试失败并出现“地址已在使用中”错误。在线程中运行此类
Listener
、释放其资源并能够使用新的
Listener
侦听同一端口来启动新线程的可靠方法是什么?除了可靠之外,还有比重复检查我尝试使用的变量
self.stopped
更优雅的方法吗?

import gc
import threading
import time

from multiprocessing.connection import Listener

class MyListener(threading.Thread):

    def __init__(self, name):
        threading.Thread.__init__(self, daemon=False)
        self.name = name
        self.address = ('localhost', 5000)
        self.stopped = False
        self.print("Object constructed")

    def run(self):
        self.print("Thread started")
        if self.stopped:
            self.print("exit run 1")
            return
        with Listener(self.address) as listener:
            self.print("Listener created")
            self.listener = listener
            if self.stopped:
                self.close()
                self.print("exit run 2")
                return
            while not self.stopped:
                with listener.accept() as conn:
                    self.conn = conn
                    if self.stopped:
                        self.close()
                        self.print("exit run 3")
                        return
                    msg = self.conn.recv()
        self.print("exit run 4")
        self.close()
        
    def close(self):
        self.print("Closing")
        self.stopped = True
        try:
            conn = self.conn
        except:
            conn = None
            self.print("No connection to close")
        if not conn is None:
            self.print("Closing connection")
            conn.close()
            del self.conn
        
        try:
            listener = self.listener
        except:
            listener = None
            self.print("No listener to close")

        if not listener is None:
            self.print("Listener closing")
            self.listener.close()
            del self.listener
            self.print("Listener closed")

        gc.collect()
        self.print("All closed")

    def print(self, text):
        thread_name = threading.current_thread().name
        if thread_name == "MainThread":
            thread_name = "M"
        print(thread_name +":" + self.name + ": " + text)


sleepseconds=1
l1 = MyListener(name="A")
time.sleep(sleepseconds)
l1.start()
time.sleep(sleepseconds)
l1.close()
time.sleep(sleepseconds)

l2 = MyListener(name="B")
time.sleep(sleepseconds)
l2.start()
time.sleep(sleepseconds)
l2.close()

我使用 python 3.12.4 的输出如下:

M:A: Object constructed
A:A: Thread started
A:A: Listener created
M:A: Closing
M:A: No connection to close
M:A: Listener closing
M:A: Listener closed
M:A: All closed
M:B: Object constructed
B:B: Thread started
Exception in thread B:
Traceback (most recent call last):
  File "/usr/lib64/python3.12/threading.py", line 1073, in _bootstrap_inner
    self.run()
  File "/home/user/PlayListener.py", line 23, in run
    with Listener(self.address) as listener:
         ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/multiprocessing/connection.py", line 464, in __init__
    self._listener = SocketListener(address, family, backlog)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/multiprocessing/connection.py", line 608, in __init__
    self._socket.bind(address)
OSError: [Errno 98] Address already in use
M:B: Closing
M:B: No connection to close
M:B: No listener to close
M:B: All closed
network-programming port python-multiprocessing python-multithreading
1个回答
0
投票

此处给出了相关问题的答案。相应的,看起来靠谱的就是替换close方法如下:

def close(self): self.stopped = True try: Client(self.address) except ConnectionRefusedError: pass try: conn = self.conn except: conn = None if not conn is None: conn.close() try: listener = self.listener except: listener = None if not listener is None: self.listener.close()
优雅仍有待发现。

© www.soinside.com 2019 - 2024. All rights reserved.