Python Socket接收/发送多线程

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

我正在编写一个Python程序,在主线程中,我一直在(循环中)使用recv函数通过TCP套接字接收数据。在回调函数中,我使用sendall函数通过同一个套接字发送数据。触发回调的原因是无关紧要的。我已将套接字设置为阻塞。

我的问题是,这样做安全吗?我的理解是在单独的线程(而不是主线程)上调用回调函数。 Python套接字对象是线程安全的吗?根据我的研究,我得到了相互矛盾的答案。

python multithreading sockets thread-safety
1个回答
1
投票

Python中的套接字不是线程安全的。

你试图立刻解决一些问题:

  1. 套接字不是线程安全的。
  2. recv阻塞并阻塞主线程。
  3. sendall正在从另一个线程使用。

您可以通过使用asyncio或以asyncio内部解决方式解决这些问题来解决这些问题:将select.selectsocketpair一起使用,并使用队列作为传入数据。

import select
import socket
import queue

# Any data received by this queue will be sent
send_queue = queue.Queue()

# Any data sent to ssock shows up on rsock
rsock, ssock = socket.socketpair()

main_socket = socket.socket()

# Create the connection with main_socket, fill this up with your code

# Your callback thread
def different_thread():
    # Put the data to send inside the queue
    send_queue.put(data)

    # Trigger the main thread by sending data to ssock which goes to rsock
    ssock.send(b"\x00")

# Run the callback thread

while True:
    # When either main_socket has data or rsock has data, select.select will return
    rlist, _, _ = select.select([main_socket, rsock], [], [])
    for ready_socket in rlist:
        if ready_socket is main_socket:
            data = main_socket.recv(1024)
            # Do stuff with data, fill this up with your code
        else:
            # Ready_socket is rsock
            rsock.recv(1)  # Dump the ready mark
            # Send the data.
            main_socket.sendall(send_queue.get())

我们在这里使用多个构造。您必须使用您选择的代码填充空白区域。至于解释:

我们首先创建一个send_queue,它是要发送的数据队列。然后,我们创建一对连接的套接字(socketpair())。我们稍后需要这个以唤醒主线程,因为我们不希望recv()阻止并阻止写入套接字。

然后,我们连接main_socket并启动回调线程。现在这里是魔术:

在主线程中,我们使用select.select来了解rsockmain_socket是否有任何数据。如果其中一个有数据,主线程就会唤醒。

在向队列添加数据后,我们通过发信号ssock唤醒主线程,rsock唤醒select.select,从而从select.select()返回。

为了完全理解这一点,你必须阅读socketpair()queue.Queue()和qazxswpoi。

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