深入netty09-write和flush为什么分离

Pipeline 事件传播

首先,回顾一下Netty中的ChannelPipeline和事件传播机制。ChannelPipeline由一系列ChannelHandler组成,分为入站处理器(ChannelInboundHandler)和出站处理器(ChannelOutboundHandler)。

  • 入站处理器:处理进入的数据,如解码、日志记录等。

  • 出站处理器:处理外出的数据,如编码、写数据到Socket等。

当调用writeAndFlush方法时,数据会在ChannelPipeline中传播,经过所有的出站处理器,最终被发送到网络。

writeAndFlush事件传播分析

writeAndFlush的调用流程如下:

  1. 调用writeAndFlush:从ChannelHandlerContext调用writeAndFlush开始事件传播。

  2. 传播到Tail节点:事件从ChannelPipeline的Tail节点开始向前传播。

  3. 处理write操作:数据首先经过write操作,被放入内存缓冲区ChannelOutboundBuffer

  4. 处理flush操作:随后flush操作触发,将缓冲区中的数据推送到Socket。

写Buffer队列

write操作并不直接发送数据到网络,而是将数据放入ChannelOutboundBuffer。这是一个链表结构的内部缓冲区,用于暂存待发送的数据。

  • Entry对象:每个待发送的数据项被封装为一个Entry对象,并加入到链表中。

  • 水位线控制ChannelOutboundBuffer通过水位线(高水位和低水位)来控制内存使用,防止溢出。

刷新Buffer队列

flush操作负责将ChannelOutboundBuffer中的数据发送到Socket:

  1. 更新指针flushedEntry指针更新,指向unflushedEntry所指向的数据,unflushedEntry置为null

  2. 发送数据:调用底层的doWrite方法,将数据从内存缓冲区写入到Socket缓冲区。

  3. 自旋锁:使用自旋锁来控制写操作的执行次数,防止长时间占用CPU资源。

ChannelChannelHandlerContext都提供了writeAndFlush方法。

它们的主要区别在于:

  • Channel.writeAndFlush:直接在Channel上调用,适用于通用的写入操作。

  • ChannelHandlerContext.writeAndFlush:在特定的ChannelHandlerContext上调用,可以访问上下文信息,如附加的属性等。

在实际使用中,推荐使用ChannelHandlerContext.writeAndFlush,因为它提供了更多的上下文信息和灵活性。

如何触发事件传播?

  1. write

    当调用 write 方法时,Netty 会将数据添加到一个内部的缓冲区(ChannelBuffer)中。这个过程是异步的,不会立即触发网络 I/O 操作。
  2. flush

    flush 方法负责将内部缓冲区中的数据发送到网络。它会触发底层的 I/O 操作,将缓冲区中的数据写入到 Socket 中。
  3. 事件传播

    writeAndFlush 调用后,Netty 的事件处理机制会将数据写入事件加入到事件队列中。随后,这些事件会被 EventLoop 线程处理,并传播给 ChannelPipeline 中的 ChannelHandler

数据写入 Socket 底层的过程

  1. 数据封装

    开发者通过 write 方法将数据封装到 ChannelBuffer 中。
  2. 数据缓存

    数据首先被缓存在 Netty 的内存中,而不是直接写入 Socket。
  3. 触发写操作

    flush 操作会触发实际的网络写操作,将缓存中的数据发送到底层的 Socket。
  4. Socket 写入

    Netty 通过 Java NIO 的 SocketChannel 将数据写入到操作系统的 Socket 缓冲区。
  5. 操作系统处理

    操作系统负责将 Socket 缓冲区中的数据发送到网络上。

为什么会有 write 和 flush 两个动作?

  • 解耦操作

    • writeflush 的分离允许更细粒度的控制数据的发送过程。

  • 性能优化

    • 通过批量发送数据(即先 write 多个数据到缓冲区,然后一次性 flush),可以减少网络 I/O 操作的次数,提高性能。

  • 灵活性

    • 开发者可以根据需要决定何时发送数据,例如,可以在收到多个消息后再一次性发送,减少网络交互次数。

数据存储和 writeAndFlush 的同步性

  • 内部缓冲

    • 在执行 flush 之前,数据被存储在 Netty 的内部缓冲区中。

  • 同步性

    • writeAndFlush 可以是同步或异步的,取决于 Channel 的配置。如果配置了自动读取(auto-read),writeAndFlush 通常是异步的。如果没有配置自动读取,它将等待数据发送完成再返回。

  • 线程安全

    • writeAndFlush 是线程安全的,可以在多个线程中调用,Netty 内部会处理并发问题。

总结

writeAndFlush 是 Netty 中用于发送数据的组合操作,它先缓存数据,然后触发网络 I/O 操作将数据发送出去。这种设计提高了数据发送的灵活性和性能,同时保证了线程安全。理解 writeflush 的分离以及它们的执行机制,有助于更好地利用 Netty 构建高效的网络应用。

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值