美文网首页
[Python]关于socket.recv()的非阻塞用法

[Python]关于socket.recv()的非阻塞用法

作者: Taraks | 来源:发表于2019-06-17 16:55 被阅读0次

Context

在写一个Socket I/O模块,功能要求如下:

  • 作为服务端,需要永远循环等待连接
  • 建立TCP连接后可以收发数据
  • 收发数据相互独立,不能阻塞

Trouble

代码如下

def run_server(send_queue, receive_queue):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind((HOST, PORT))
        s.listen(1)
        conn, addr = s.accept()
        print(f"[server] Connecting with {addr}")
        with conn:
            while True:
                try:
                    m = send_queue.get(block=False)
                except queue.Empty as e:
                    m = None
                if m:
                    print(isinstance(m, AbstractMessage))
                    if isinstance(m, AbstractMessage):
                        send_bytes = message2bytes(m)
                        conn.sendall(send_bytes)
                        print(f"Send message is {type(m)} : {send_bytes}")
                try:
                    data = conn.recv(4096)
                except BlockingIOError as e:
                    data = None
                if data:
                    print(f"data is {data}")
                    receive_message = bytes2message(data)
                    print(f"Receive message is {receive_message}")
                    receive_queue.put(receive_message)
                    BUS.push(receive_message)

调试时发现当Client没有发送数据时,Server会阻塞地等待接收数据,也就是data = conn.recv(4096)这一行代码,导致无法发送数据。

Solution

查阅queue — A synchronized queue class
后,得知recv()方法需要传入两个参数,bufsizeflags

Receive data from the socket. The return value is a bytes object representing the data received. The maximum amount of data to be received at once is specified by bufsize. See the Unix manual page recv(2) for the meaning of the optional argument flags; it defaults to zero.

文档内只描述了bufsize的用法,关于flags只是一笔带过。
在StackOverflow的When does socket.recv(recv_size) return?问题中@Ray的回答:

You can also call recv() as nonblocking if you give the right flag for it: socket.recv(10240, 0x40) # 0x40 = MSG_DONTWAIT a.k.a. O_NONBLOCK Please note that you have to catch the [Errno 11] Resource temporarily unavailable exceptions when there is no input data.

得知通过flags参数可以将recv()方法设置为MSG_DONTWAIT,通过try-except写法可以实现非阻塞。
代码如下:

try:
    data = conn.recv(4096, 0x40)
except BlockingIOError as e:
    data = None

tips: 在查阅了recv(2) - Linux man page文档后依然没能找到0x40MSG_DONTWAIT的对照表。

Sunmmary

Python的socket.recv()方法可以通过传入flags=0x40参数配合try-except方法实现非阻塞。

相关文章

  • [Python]关于socket.recv()的非阻塞用法

    Context 在写一个Socket I/O模块,功能要求如下: 作为服务端,需要永远循环等待连接 建立TCP连接...

  • socket.recv

    本文仅讨论阻塞socket的情况。在v2ex上看到了2个提问,socket.recv 完整接收数据、python ...

  • socket

    1、socket的非阻塞用法 使用setblocking(0)之后就变成了非阻塞的socket连接? 而使用se...

  • 关于python中同步、异步,阻塞、非阻塞的理解

    异步:某个事情需要10秒。而我只需要调用一个函数帮我做,我可以干其他的事情。(比如调用celery) 同步:某个事...

  • 谈论:同步异步阻塞非阻塞.md

    同步/异步:关注的方式(是否主动) 阻塞/非阻塞: 同步阻塞BIO: 同步非阻塞NIO: 异步非阻塞: 异步阻塞:

  • Java IO 学习(一)同步/异步/阻塞/非阻塞

    关于IO,同步/异步/阻塞/非阻塞,这几个关键词是经常听到的,譬如:“Java oio是阻塞的,nio是非阻塞的”...

  • 进程 线程 协程 同步 异步 阻塞 非阻塞

    参考文章: Python 中的进程、线程、协程、同步、异步、回调 简明网络I/O模型---同步异步阻塞非阻塞之惑...

  • 我所理解的Java NIO

    这两天了解了一下关于NIO方面的知识,网上关于这一块的介绍只是介绍了一下基本用法,没有系统的解释NIO与阻塞、非阻...

  • 这一篇带你深入理解Java NIO

    这两天了解了一下关于NIO方面的知识,网上关于这一块的介绍只是介绍了一下基本用法,没有系统的解释NIO与阻塞、非阻...

  • 23、pythonIO模型

    python之路——IO模型 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步、异步、阻塞、非阻塞 ...

网友评论

      本文标题:[Python]关于socket.recv()的非阻塞用法

      本文链接:https://www.haomeiwen.com/subject/hekafctx.html