Netty

作者: 16325 | 来源:发表于2020-02-17 13:53 被阅读0次

TCP 粘包/拆包

  • 当通过TCP协议传输多次数据的时候,TCP协议会把一些消息合并发送,来节省IP调用次数,这样的话,可能有一些消息就是多条消息的组合,有的消息也可能配拆开分成两条消息。
  • 在Netty中,已经造好了许多类型的拆包器,我们直接用就好:


    image.png

    选好拆包器后,在代码中client段和server端将拆包器加入到chanelPipeline之中就好了:
    客户端:

ch.pipeline().addLast(new FixedLengthFrameDecoder(31));
服务端:
ch.pipeline().addLast(new FixedLengthFrameDecoder(31));

零拷贝

传统意义的拷贝是在发送数据的时候,传统的实现方式是:

  1. File.read(bytes)
  2. Socket.send(bytes)
    这种方式需要四次数据拷贝和四次上下文切换:
  3. 数据从磁盘读取到内核的read buffer
  4. 数据从内核缓冲区拷贝到用户缓冲区
  5. 数据从用户缓冲区拷贝到内核的socket buffer
  6. 数据从内核的socket buffer拷贝到网卡接口(硬件)的缓冲区

零拷贝的概念

明显上面的第二步和第三步是没有必要的,通过java的FileChannel.transferTo方法,可以避免上面两次多余的拷贝(当然这需要底层操作系统支持)

  1. 调用transferTo,数据从文件由DMA引擎拷贝到内核read buffer
  2. 接着DMA从内核read buffer将数据拷贝到网卡接口buffer上面的两次操作都不需要CPU参与,所以就达到了零拷贝。

Netty中的零拷贝

主要体现在三个方面:
1、bytebufferNetty发送和接收消息主要使用bytebuffer,bytebuffer使用对外内存(DirectMemory)直接进行Socket读写。原因:如果使用传统的堆内存进行Socket读写,JVM会将堆内存buffer拷贝一份到直接内存中然后再写入socket,多了一次缓冲区的内存拷贝。DirectMemory中可以直接通过DMA发送到网卡接口
2、Composite Buffers传统的ByteBuffer,如果需要将两个ByteBuffer中的数据组合到一起,我们需要首先创建一个size=size1+size2大小的新的数组,然后将两个数组中的数据拷贝到新的数组中。但是使用Netty提供的组合ByteBuf,就可以避免这样的操作,因为CompositeByteBuf并没有真正将多个Buffer组合起来,而是保存了它们的引用,从而避免了数据的拷贝,实现了零拷贝。
3、对于FileChannel.transferTo的使用Netty中使用了FileChannel的transferTo方法,该方法依赖于操作系统实现零拷贝。

Netty 内部执行流程

image.png image.png

1、创建ServerBootStrap实例
2、设置并绑定Reactor线程池:EventLoopGroup,EventLoop就是处理所有注册到本线程的Selector上面的Channel
3、设置并绑定服务端的channel
4、5、创建处理网络事件的ChannelPipeline和handler,网络时间以流的形式在其中流转,handler完成多数的功能定制:比如编解码 SSl安全认证
6、绑定并启动监听端口
7、当轮训到准备就绪的channel后,由Reactor线程:NioEventLoop执行pipline中的方法,最终调度并执行channelHandler

客户端

image.png
image.png

相关文章

网友评论

      本文标题:Netty

      本文链接:https://www.haomeiwen.com/subject/biybfhtx.html