zoukankan      html  css  js  c++  java
  • Netty如何封装Socket客户端Channel,Netty的Channel都有哪些类型?

     

    更多技术分享可关注我

    前言

    原文:Netty如何封装Socket客户端Channel,Netty的Channel都有哪些类型?

    前面分析过Netty封装的服务端Channel——NioServerSocketChannel,对应的客户端也会封装一个Channel——NioSocketChannel,可以对比OIO网络编程模型中的ServerSocket和Socket,对应NIO中的ServerSocketChannel和SocketChannel,看看这两个组件是如何被Netty封装使用的。

    Netty封装客户端SocketChannel的源码分析

    如下是Netty服务端读取新连接的核心代码,在文章:Netty是如何处理新连接接入事件的?中已经总结分析过:

    在黄色1处获取了JDK的SocketChannel后,在黄色2处Netty调用了NioSocketChannel的构造器,目的是将JDK的SocketChannel封装为Netty自己的客户端Channel——NioSocketChannel。下面跟进源码,看看Netty都封装了什么东西,以及为何要这么做。

    总的来说,NioSocketChannel的构造器主要做了两件事:

    1、调用一系列父类构造器,对SocketChannel做初始化工作

    • 设置SocketChannel为非阻塞模式

    • 保存初始化SocketChannel需要注册的I/O事件——OP_READ=16

    • 创建SocketChannel的唯一id

    • 创建SocketChannel的unsafe实现类——NioByteUnsafe,后续专门总结Netty的unsafe,这里先知道。

    • 创建SocketChannel的默认pipeline组件,这个组件是Netty额外封装JDK的Channel的核心原因,目的就是更好的设计自己的架构,这里和服务端封装ServerSocketChannel是一样的逻辑,复用了代码

    2、调用配置类:主要是禁止TCP Nagle算法

    下面看下细节,下面是NioSocketChannel的构造器源码:

    首先,层层调用父类构造器对其初始化,复习Netty Channel的继承关系:

    比如先调用直接父类——AbstractNioByteChannel构造器,该构造器会将SocketChannel的I/O读事件保存:

    然后继续调用父类构造器——AbstractNioChannel,这里和Netty封装服务端Channel——NioServerSocketChannel,共用了一段逻辑:

    主要做了三件事:

    1、保存JDK的SocketChannel,也就是AbstractNioChannel中的ch属性

    2、为Netty封装的Channel保存interest的I/O事件

    3、设置JDK的SocketChannel为非阻塞模式

    当然在做这三件事前,会继续先调用上层父类AbstractChannel的构造器:

    该构造器主要作用是初始化Netty客户端Channel的一些共有配置,比如唯一id,大动脉pipeline组件,以及为其创建unsafe,和封装服务端Channel一样的流程

    全部搞完,返回到NioSocketChannel构造器,继续执行如下初始化config属性的逻辑:

    这里初始化config,最重要的一件事是禁止了TCP的Nagle算法,如下代码:

    至于何时才会自动关闭该算法,需要看if判断逻辑里的判断方法——canEnableTcpNoDelayByDefault是什么东西,如下:

    发现一个默认的变量CAN_ENABLE_TCP_NODELAY_BY_DEFAULT,它在非安卓环境下设置为关闭,即在非安卓端上部署Netty,它会自动关闭TCP的nagle算法。

    TCP协议默认开启了Nagle算法(即默认关闭TCP_NODELAY选项,注意意思是相反的)

    Netty客户端NioSocketChannel的创建很简单,至此分析完毕。

    小结

    Netty封装客户端NioSocketChannel主要就是三件事:

    1、配置SocketChannel为非阻塞——configureBlocking(false)

    2、保存OP_READ事件,但是是延迟注册的,且会为Channel创建唯一id,unsafe组件(负责底层数据读写)和pipeline组件(业务数据流动的载体)

    3、在NioSocketChannelConfig()中判断设置是否打开TCP的Nagle算法,即在非安卓环境下,执行setTcpNoDelay(true),即禁止Nagle算法,希望把小数据包尽量发送出去,降低延迟,而Nagle算法会通过减少需要传输的数据包来优化网络。在Linux内核中,数据包的发送和接受会先做缓存,分别对应于写缓存和读缓存。目的是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

    Netty的Channel类型总结

    下面全面总结一下Netty的Channel类型,当然主要是NIO模型下的Channel。Netty的NIO模型的Channel主要分为两类:NioSocketChannel和NioServerSocketChannel,分别封装了JDK的SocketChannel和ServerSocketChannel,对应了客户端Socket和服务端Socket。

    一个精简版的类图如下,蓝色部分是服务端Channel,白色是客户端的Channel。

    我们只关心对JDK NIO的封装设计,从顶到下,基本脉络是:Channel接口>AbstractChannel(所有Channel的骨架实现)>AbstractNioChannel(NIO模型下Channel的骨架),而从AbstractNioChannel又开始分支,如下:

    Channel是Netty的所有Channel的共同接口,定义了一系列的Socket或者Netty自身的I/O操作的接口,而Channel的底层I/O功能的实现都是由Unsafe接口负责,该接口聚合在了Channel接口,作为其内部接口。

    AbstractChannel是Channel的骨架实现,负责实现不同类型Channel的共同组件或者基础属性,比如保存Channel的标识id,unsafe骨架实现,pipeline,EventLoop属性等。

    AbstractNioChannel是NIO模型下Channel的骨架实现,相对的,阻塞模型下Channel的骨架实现就是AbstractOioChannel,这很少有人用,不讨论它。AbstractNioChannel最大的特性是聚合了JDK的I/O多路复用器——Selector,主要负责NIO相关的Channel的抽象实现,且内置了JDK底层的Channel接口,可以给客户端/服务端Channel设置非阻塞模式,保存interest的I/O事件,SelectionKey等,前面分析过这个构造器。

    从AbstractNioChannel后,开始细分服务端和客户端的Channel:

    主要就是这两类Channel,它们都直接继承AbstractNioChannel,两者最明显的区别是默认设置的I/O事件不一样,NioSocketChannel是设置OP_READ事件,而NioServerSocketChannel是设置OP_ACCEPT事件,即前者是读取已建立连接上的数据,后者是读取新连接。

    还有一个Unsafe,前面说过每个Netty的Channel都有一个Unsafe接口与之绑定,Unsafe接口的相关实现类负责实现Netty的Channel所有I/O操作,一共有两类unsafe的实现类,即服务端Channel的NioMessageUnsafe,它的主要作用就是读新连接,还有客户端Channel的NioByteUnsafe,它的主要作用是读、写已有连接上的数据,复习下两者的继承关系:

    最后,还能知道每个Netty的Channel都有一个config——配置工具类,存储了每类Channel的底层网络配置,其继承关系如下:

    整个结果一气呵成,充分利用了模板方法等设计模式,不论是命名上,还是具体实现上,都非常美观和流畅,可以学习这种组件分类设计的方式。

    小结

    NIO模型下,Netty中的Channel分类:

    1、NioServerSocketChannel是服务端Channel,继承AbstractNioMessageChannel,启动时注册的I/O事件为OP_ACCEPT,并创建NioServerSocketChannelConfig和NioMessageUnsafe,核心作用就是读新客户端连接

    2、NioSocketChannel是客户端Channel,继承AbstractNioByteChannel,初始化时注册的I/O事件为OP_READ,创建NioSocketChannelConfig和NioByteUnsafe,核心作用是读、写已有连接上的数据

    欢迎关注

    dashuai的博客是终身学习践行者,大厂程序员,且专注于工作经验、学习笔记的分享和日常吐槽,包括但不限于互联网行业,附带分享一些PDF电子书,资料,帮忙内推,欢迎拍砖!

  • 相关阅读:
    2.1 Python介绍
    2.2 Python基础知识
    内网渗透的一些工具和平台汇总
    ABC技术落地_成功带动lot物联网行业、金融科技行业、智能人才教育。
    舆情、网络舆情、舆情分析
    XSSer:自动化XSS漏洞检测及利用工具
    10款开源安全工具
    系统管理员资源大全,学习学习学习(转载)
    如何搭建邮件服务器
    域名常见名词解释
  • 原文地址:https://www.cnblogs.com/kubixuesheng/p/12723428.html
Copyright © 2011-2022 走看看