首页 文章

Python Socket接收/发送多线程

提问于
浏览
3

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

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

1 回答

  • 0

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

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

    • 套接字不是线程安全的 .

    • recv阻塞并阻塞主线程 .

    • 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() .

相关问题