23-使用非阻塞IO-2

阻塞IO的写(short write)

读:对于非阻塞的读,如果读数据不全,我们需要将数据缓存,等凑够一条完整消息再触发消息处理逻辑。

写:

  • 将需要发送的数据先传到buffer,然后再从buffer发送数据

  • 开始关注POLLOUT事件,需要write时,要先将数据写到buffer

  • 发送策略:

    • 1:当有数据要发送,可以先write,如果未写完,则将剩余数据存到缓冲区,并且关注POLLOUT事件

    • 2:任何时候有数据都必须放到缓冲区中,通过关注POLLOUT事件,来发送

  • 当buffer为空,停止关注POLLOUT事件,否则会造成busy loop

 

如何处理非阻塞IO中对方接受缓慢

image-20230218225021404

用一个形象的例子来描述:水盆(缓冲区),下方有个去水口(读、取走数据),上方有个水龙头(写、发进数据)。当水龙头流量过大时,去水口来不及排水,这时,要么让水一直上升,直至溢出(数据丢失),要么加高水盆(换更大的缓冲区)来保存更多的水。

有一个更好的策略,设置高水位(high water mark)和低水位(low water mark)。当水位高于高水位时将水龙头关闭,排水,当水位低于低水位时,再将水龙头打开。

 

但这终究不是一个完美的解决方案,对于接收端大量频繁的请求而言,我们不 read() 这些请求并不是一个好的解决方案,最好的方式是接收两方进行协议层面的商定,通过滑动窗口的思想告知接收端是否可以开启下一次的请求。这样方可避免由于接收方大量的数据请求而造成发送端发缓冲区数据的大量堆积(比如,接收端每次get image请求,发送端将对应image数据发送给接收端。对于接收端而言发送一次请求耗费的数据量很少,而发送发要回应的每个请求的数据量等很大,如果发送方一次接收到多个请求则这些应答数据将会占满发送发的缓冲区)。

 

 

LT 或者 ET?

  • poll和select都是LT,而且许多第三方库由于历史原因也是LT

  • epoll支持LT和ET,但是没有证据说明二者谁更快

  • ET:更适合accept和write。

    • 从编码角度,accept和write更适合ET。accept如果文件描述符用完,会陷入死循环中,因此使用模式更好

  • LT:更适合read。

    • 从编码角度,read更适合LT。它不会造成接收的饥饿,ET模式可能会造成数据接收不完整的情况。

  • 理想状况,同一个socket,就是将写用ET,将读用LT。但是Linux不支持,只能一个socket用一种。

posted @ 2023-04-29 15:52  DavidJIAN  阅读(16)  评论(0)    收藏  举报