我正在编写一个Python程序,其中在我的主线程中,我使用recv函数连续地(循环地)通过TCP套接字接收数据。在回调函数中,我正在使用sendall函数通过同一套接字发送数据。触发回调的无关紧要。我已将套接字设置为阻塞。
我的问题是,这样做安全吗?我的理解是,回调函数是在单独的线程(不是主线程)上调用的。 Python套接字对象是线程安全的吗?从我的研究中,我得到了矛盾的答案。
答案 0 :(得分:1)
Python中的套接字不是线程安全的。
您正在尝试一次解决一些问题:
您可以通过使用asyncio来解决这些问题,也可以使用asyncio在内部解决它的方式来解决这些问题:通过将select.select
与socketpair
一起使用,并为输入数据使用队列。
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
来了解rsock
或main_socket
是否包含任何数据。如果其中之一具有数据,则主线程将唤醒。
将数据添加到队列后,我们通过发信号通知ssock
并唤醒rsock
并由此从select.select
返回的信号来唤醒主线程。
要完全理解这一点,您必须阅读select.select()
,socketpair()
和queue.Queue()
。