blocking socket 读写返回 EAGAIN

非阻塞的 socket 读写操作返回 EAGAIN,表示当前已经读完内核缓冲区或者写满内核缓冲区,需要等待下一次 select/poll/epoll 事件到来时再操作。

对于阻塞的 socket 读写操作,如果内核缓冲区是空,read 将一直阻塞;如果不能一下全部写入用户态缓冲区的所有数据,write 将阻塞。原以为对于阻塞的 socket,如果设置超时时间,读操作内核缓冲区为空或写操作内核缓冲区已满,返回的是 ETIMEDOUT,原来返回的也是 EAGAIN.

内核缓冲区还有 4 个字节的剩余空间,那么对于阻塞操作,如果需要写入 6 个字节,就会一直阻塞,直到 6 个字节全部写入内核缓冲区;如果设置超时,那么第一次写入会直接返回 4,表示写入了 4 个字节;第二次写入操作才返回 EAGAIN.

那么总结起来,对于 socket 操作,返回 EAGAIN 的有如下 3 钟情况。

  1. explicitly marking the file descriptor as nonblocking with fcntl();
  2. passing the MSG_DONTWAIT flag to send()
  3. setting a send timeout with the SO_SNDTIMEO socket option

 

下边一系列实验都是在当前本端发送缓冲区已满的情形下进行并且在此过程中,对端不进行读取操作。

1、socket 的写入操作会一直阻塞,使用 ctrl + C终止。

blocking socket 读写返回 EAGAIN_第1张图片

2、阻塞套接字设置 MSG_DONTWAIT 标志,表示本次操作非阻塞,立即返回 EAGAIN,在python 里就是抛 BlockingIOError.

blocking socket 读写返回 EAGAIN_第2张图片

3、阻塞套接字设置 SO_SNDTIMEO 发送超时选项,阻塞直到超时后返回,在python 里就是抛 BlockingIOError.

blocking socket 读写返回 EAGAIN_第3张图片

4、在 python 里,单独有个方法可以设置超时:.settimeout(),次方法不是通过设置套接字选项来实现的。下边的代码片段先关闭通过套接字选项设置的超时(通过给选项参数设置为 0),然后通过 .settimeout 方法设置超时,注意超时时,抛出的是 timeout异常,errno 并没有被设置。

blocking socket 读写返回 EAGAIN_第4张图片

 

 

 

你可能感兴趣的:(TCPIP,python)