Skip to main content
 首页 » 编程设计

python之Python套接字对象是线程安全的吗

2025年05月04日7shangdawei

我正在计划设计一种如下工作的UDP服务器:我将与位于防火墙后面且需要能够随时发送数据的客户端进行通信。因此,客户端将首先启动与我的连接,并通过定期发送保持 Activity 的数据包来使连接保持 Activity 状态。当我收到一个时,我需要确认它。同时,如果我有任何要发送的数据,则需要立即发送。我整理了以下测试代码:

import threading 
import queue 
import socket 
import time 
 
class SharedAddress(): 
    def __init__(self): 
        self.lock = threading.Lock() 
        self.addr = () 
 
    def set_addr(self, addr): 
        self.lock.acquire() 
        self.addr = addr 
        self.lock.release() 
 
    def get_addr(self): 
        self.lock.acquire() 
        addr = self.addr 
        self.lock.release() 
        return addr 
 
class Reader(threading.Thread): 
    def __init__(self, socket, shared_address): 
        super().__init__(name='Reader Thread') 
        self.socket = socket 
        self.shared_address = shared_address 
 
    def run(self): 
        while True: 
            # Wait for data from the client 
            data, addr = self.socket.recvfrom(4096) 
            #print("Received data from {}".format(addr)) 
            # Echo it back 
            self.socket.sendto(data, addr) 
            self.shared_address.set_addr(addr) 
 
class Writer(threading.Thread): 
    def __init__(self, socket, shared_address): 
        super().__init__(name='Writer Thread') 
        self.socket = socket 
        self.tx_queue = queue.Queue() 
        self.shared_address = shared_address 
 
    def run(self): 
        while True: 
            # Wait for data to be received 
            data = self.tx_queue.get() 
            # Send it to the client 
            addr = self.shared_address.get_addr() 
            if addr: 
                self.socket.sendto(data, addr) 
 
 
 
### Main loop 
# Create the socket 
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
s.bind(('', 2000)) 
 
sa = SharedAddress() 
 
r = Reader(s, sa) 
w = Writer(s, sa) 
 
r.start() 
w.start() 
 
while True: 
    w.tx_queue.put(b'>>Hi this is a message<<\n') 
    time.sleep(0.1) 
 
r.join() 
w.join() 
 
print("Program ended") 

尽管代码似乎可以正常工作,但是我担心的是,我正在使用来自两个不同线程的相同套接字对象,而没有任何形式的锁定。然后,我修改了Writer类以创建自己的套接字对象:
class Writer(threading.Thread): 
    def __init__(self, shared_address): 
        super().__init__(name='Writer Thread') 
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
        self.tx_queue = queue.Queue() 
        self.shared_address = shared_address 

这似乎也很好。我的问题如下:
  • 套接字对象线程安全吗?
  • 如果您在Python中创建了多个UDP套接字对象,并使用它们将数据发送到相同的地址,它们实际上是否最终引用了相同的基础连接对象?
  • 如果我在其中一个套接字对象上调用close命令,会发生什么情况?大概它将关闭底层的OS套接字,并防止其他套接字对象接收和发送。
  • 请您参考如下方法:

    如果需要,可以使用zmq

    PyZMQ