本文首先借用陈硕老师关于非阻塞网络编程中buffer的必要性的论述。然后再深入源码,分析buffer的实现
Tcpconnection必须要有outputbuffer:
想像一个场景:应用程序想向TCP连接发送100k数据,但是在write系统调用中,操作系统只接受80k数据。为了避免阻塞,我们肯定不想在这里阻塞。因为不知道要等多久。程序应该尽快交出控制权,返回eventloop,此时,剩下的20k数据怎么办?
对于应用程序而言,它只管生成数据,不应该关心到底数据是一次性发送还是分成多次发送。这些问题应该由网络库关心。应用程序只需要直接调用Tcpconnection::send()就可以,网络库负责接管剩下的20k数据,把它保存在TcpConnection的buffer中,然后注册POLLOUT事件,一旦POLLOUT事件发生就可以直接将剩下的数据发送出去。当然,第二次调用也不能确定可以写完20k数据。如果还有剩余数据,网络库继续关注POLLOUT事件。如果buffer中已经没有数据可发送了,则取消对POLLOUT事件的关注,避免造成busy loop。
如果程序又写入50k数据,而这时候Tcpconnection缓冲区中还有20k数据等待发送,那么网络库不应该直接调用write,而应该把这50k的数据append到原来的20k数据之后,等socke可写时再一起写入。
如果outbuffer中还有待发送的数据,而程序又想关闭连接,那么这时候网络库不能立即关闭,而要等待缓冲区数据发送完毕再关闭。
综上,要让程序在write操作上不阻塞,网络库必须要给每个tcp connection配置output buffer。
TcpConnection必须要有input buffer
Tcp是一个无边界的字节流协议。接收方必须处理收到的数据尚不构成一条完整的消息和一次收到两条消息的数据等情况。而且网络库在读取socket可读事件时,必须一次性把so