Buffer类的设计

应用层缓冲区Buffer设计

muduo的I/O模型是I/O复用,并且文件描述符设置为非阻塞模式,因为如果使用阻塞模式,I/O线程就有可能阻塞在read、write这些系统调用之上,这样一来,即使其它描述符的IO事件到来,IO线程也不能立刻去处理,也就不能最大程度的使用IO线程。 

 

为什么TcpConnection必须要有output buffer?

考虑一个常见场景:程序想通过 TCP 连接发送 100k 字节的数据,但是在 write() 调用中,操作系统只接受了 80k 字节,我们知道write()的返回不代表消息已经到了对等方,仅仅表示数据从用户空间到了内核空间,还受 TCP advertised window 的控制,所以不一定这100k字节就到了内核的发送缓冲区中,你肯定不想在原地等待,因为不知道会等多久(取决于对方什么时候接受数据,然后滑动 TCP 窗口)。程序应该尽快交出控制权,返回 event loop。在这种情况下,剩余的 20k 字节数据怎么办?应该添加到应用层的发送缓冲区。    

对于应用程序而言,它只管生成数据,它不应该关心到底数据是一次性发送还是分成几次发送,这些应该由网络库来操心,程序只要调用 TcpConnection::send() 就行了,网络库会负责到底。网络库应该接管这剩余的 20k 字节数据,把它保存在该 TCP connection 的 output buffer 里,然后注册 POLLOUT 事件,一旦 socket 变得可写就立刻发送数据。就可以把应用层output buffer里面的数据拷贝到内核中的发送缓冲区 。当然,这第二次 write() 也不一定能完全写入 20k 字节,如果还有剩余,网络库应该继续关注 POLLOUT 事件;如果写完了 20k 字节,网络库应该停止关注 POLLOUT,以免造成 busy loop。(Muduo EventLoop 采用的是 epoll level trigger,这么做的具体原因我以后再说。)

如果程序又写入了 50k 字节,而这时候 output buffer 里还有待发送的 20k 数据,那么网络库不应该直接调用 write(),而应该把这 50k 数据 append 在那 20k 数据之后,等 socket 变得可写的时候再一并写入。

如果 output buffer 里还有待发送的数据,而程序又想关闭连接(对程序而言,调用 TcpConnection::send() 之后他就认为数据迟早会发出去),那么这时候网络库不能立刻关闭连接,而要等数据发送完毕。
 

综上,要让程序在 write 操作上不阻塞,网络库必须要给每个 tcp connection 配置 output buffer。

为什么TcpConnection必须要有input buffer?

TCP 是一个无边界的字节流协议,接收方必须要处理“收到的数据尚不构成一条完整的消息”和“一次收到两条消息的数据”等等情况。一个常见的场景是,发送方 send 了两条 10k 字节的消息(共 20k),接收方收到数据的情况可能是:

一次性收到 20k 数据
分两次收到,第一次 5k,第二次 15k
分两次收到,第一次 15k,第二次 5k
分两次收到,第一次 10k,第二次 10k
分三次收到,第一次 6k,第二次 8k,第三次 6k
其他任何可能

网络库在处理“socket 可读”事件的时候,必须一次性把 socket 里的数据读完(从操作系统 buffer 搬到应用层 buffer),否则会反复触发 POLLIN 事件,造成 busy-loop。

那么网络库必然要应对“数据不完整”的情况,收到的数据先放到 input buffer 里,等构成一条完整的消息再通知程序的业务逻辑。也就是说,接受到数据,存至input buffer,通知上层的应用程序,onMessage(Buffer *buff)回调,根据应用层协议判定是否是一个完整的包,如果不是一条完整的消息,不会取走数据,也不会相应的处理,如果是一条完整的消息,将取走这条消息,并进行相应的处理。怎么判断是完整的消息,就是上层应用程序的事了。
 

所以,在 tcp 网络编程中,网络库必须要给每个 tcp connection 配置 input buffer。

所有 muduo 中的 IO 都是带缓冲的 IO (buffered IO

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值