Python套接字接收/发送多线程

时间:2018-06-29 14:58:10

标签: python multithreading sockets thread-safety

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

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

1 个答案:

答案 0 :(得分: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()