Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python套接字接收/发送多线程_Python_Multithreading_Sockets_Thread Safety - Fatal编程技术网

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

Python套接字接收/发送多线程,python,multithreading,sockets,thread-safety,Python,Multithreading,Sockets,Thread Safety,我正在编写一个Python程序,在主线程中,我使用recv函数通过TCP套接字连续(在循环中)接收数据。在回调函数中,我使用sendall函数通过同一套接字发送数据。触发回调的因素无关紧要。我已将套接字设置为阻塞 我的问题是,这样做安全吗?我的理解是,回调函数是在单独的线程(而不是主线程)上调用的。Python套接字对象是线程安全的吗?从我的研究中,我得到了相互矛盾的答案。Python中的套接字不是线程安全的 您试图同时解决几个问题: 套接字不是线程安全的 recv正在阻塞并阻塞主线程 正在从其

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


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

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

您试图同时解决几个问题:

  • 套接字不是线程安全的
  • recv正在阻塞并阻塞主线程
  • 正在从其他线程使用sendall
  • 您可以使用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\u队列
    ,它是一个要发送的数据队列。然后,我们创建一对连接的套接字(
    socketpair()
    )。稍后我们需要它来唤醒主线程,因为我们不希望
    recv()
    阻塞和阻止对套接字的写入

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

    在主线程中,我们使用
    select.select
    来了解
    rsock
    main\u socket
    是否有任何数据。如果其中一个有数据,主线程将被唤醒

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


    为了完全理解这一点,您必须阅读,并且。

    这里有一些隐藏的问题,您正试图立即解决。希望我给了你一个详细的答案,但是可以自由地问你是否理解。考虑使用异步I/O来处理你的用例,那么你就不需要线程了。我实际上在使用MyPython,它看起来像MyPython不支持Socket。这有什么关系吗?也许创建一个类似的函数,或者只是创建两个附加的套接字?谢谢@Alon
    socketpair
    的操作与在本地主机上创建2个套接字几乎相同。您可以创建2个套接字,也可以设置一个较低的
    select。选择
    timeout并轮询。我显然不喜欢轮询选项,因为它浪费资源,速度较慢,如果您已经在运行MicroPython,我想您这样做是有原因的,轮询会很糟糕。选择两个额外的套接字。@请记住,在unix上选择。选择也适用于任何其他文件描述符,而不仅仅是套接字。如果fd对您有任何帮助,您可以使用不同的fd,但我不认为这样做有什么好处(我想管道会更高效一些,但不值得为此破坏交叉兼容性)。如果我需要创建两个额外的套接字(总共三个),只创建两个TCP套接字连接是否更好,一个用于输入,一个用于输出?它需要更少的一个套接字,并且可能更容易编码。
    选择器
    模块更好