Netty学习(三)-Netty重要接口讲解

【Netty】模型篇三:Netty核心组件讲解 本文针对上一篇文章 【Netty】模型篇二:通过案例分析Netty线程模型以及Netty的核心组件 中涉及到的Netty核心组件进行分析讲解。 注意:这里强烈建议大家先学习一下 Java NIO,再来看本文。 阅读详情

上一节我们写了一个HelloWorld,对于Netty的运行有了一定的了解,知道Netty是如何启动客户端和服务器端。这一节我们简要的讲解一下几个重要的接口,初步探讨Netty的运行机制,当然刚学Netty就深入原理肯定是很枯燥的,所以我们就点到为止。

1. ChannelPipeLine和ChannelHandler

在上一篇中我们在ChannelInitializer类的initChannel方法中使用了ChannelPipeline,然后在ChannelPipeline中使用了handler来处理业务逻辑。

ChannelPipeline是ChannelHandler的容器,它负责ChannelHandler的管理和事件拦截与调度。Netty的ChannelPipeline和ChannelHandler机制类似于Servlet 和Filter 过滤器,这类拦截器实际上是职责链模式的一种变形,主要是为了方便事件的拦截和用户业务逻辑的定制。

Netty的channel运用机制和Filter过滤器机制一样,它将Channel 的数据管道抽象为ChannelPipeline. 消息在ChannelPipeline中流动和传递。ChannelPipeline 持有I/O事件拦截器ChannelHandler 的链表,由ChannelHandler 对I/0 事件进行拦截和处理,可以方便地通过新增和删除ChannelHandler 来实现小同的业务逻辑定制,不需要对已有的ChannelHandler进行修改,能够实现对修改封闭和对扩展的支持。

通过一张图我们来看一下他们之间的关系: 

一个Channel中包含一个ChannelPipeline,用来处理Channel中的事件,一个ChannelPipeline中可以包含很多个handler,第二节的示例代码中我们也看到了,使用各种handler来处理通信信息。

同时我们也注意到在hadler中继承了ChannelInboundHandlerAdapter类并实现了他的一些方法,比如:channelRead,channelActive,channelInactive等等,我们看到这些方法中都有一个参数:ChannelHandlerContext ctx。这个ChannelHandlerContext就是handler的上下文对象,有了这个ChannelHandlerContext你就获得了一切,你可以获得通道,获得事件的控制权。

事实上,用户不需要自己创建pipeline,因为使用ServerBootstrap 或者Bootstrap 启动 
服务端或者客户端时, Netty 会为每个Channel 连接创建一个独立的pipeline。

ChannelPipeline pipeline = socketChannel.pipeline();

pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192,Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());

// 客户端的逻辑
pipeline.addLast("handler", new HelloWorldClientHandler());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

ChannelPipeline 是线程安全的, 这意味着N个业务线程可以并发地操作ChannelPipeline 
而不存在多线程并发问题。但是,ChannelHandler却不是线程安全的,这意味着尽管 
ChannelPipeline 是线程去全的, 但是仍然需要自己保证ChannelHandler的线程安全。

Netty 中的事件分为inbound 事件和outbound 事件。inbound 事件通常由I/O线程触发,例如TCP 链路建立事件、链路关闭事件、读事件、异常通知事件等。Outbound 事件通常是I/O 用户主动发起的网络I/O 操作,例如用户发起的连接操作、绑定操作、消息发送等操作。

我们常用的inbound事件有:

  • ChannelHandlerContext fireChannelRegistered() //channel注册事件
  • ChannelHandlerContext fireChannelActive() //channel激活事件
  • ChannelHandlerContext fireExceptionCaught(Throwable var1) //channel异常处理事件
  • ChannelHandlerContext fireUserEventTriggered(Object var1) //用户自定义事件
  • ChannelHandlerContext fireChannelRead(Object var1) //读事件

pipeline 中以fireXXX命名的方法都是从I/O 线程流向用户业务Handler的inbound 事件,它们的实现因功能而异,但是处理步骤类似:

  1. 调用HeadHandler对应的fireXXX 方法

  2. 执行事件相关的逻辑操作

常用的outbound事件有:

  • ChannelFuture bind(SocketAddress var1, ChannelPromise var2) //绑定地址
  • ChannelFuture connect(SocketAddress var1, ChannelPromise var2) //连接服务器
  • ChannelFuture write(Object var1) //发送事件
  • ChannelHandlerContext flush() //刷新事件

上面我们说到事件,netty的事件机制是由前至后的,一般来说,都是一个channel的ChannnelActive方法中调用fireChannelActive来触发调用下一个handler中的ChannelActive方法,即你在ChannelPipeline中添加handler的时候,要在第一个handler的channelActive方法中调用fireChannelActive,以此来触发下一个事件。我们再来写一个案例说明一下:

客户端:

public class HWClient {
    private  int port;
    private  String address;

    public HWClient(int port, String address) {
        this.port = port;
        this.address = address;
    }

    public void start(){
        EventLoopGroup group = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ClientChannelInitializer());

        try {
            ChannelFuture future = bootstrap.connect(address,port).sync();
            future.channel().writeAndFlush("Hello Netty Server ,I am a common client");
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }

    }

    public static void main(String[] args) {
        HWClient client = new HWClient(7788,"127.0.0.1");
        client.start();
    }
}
  •  

客户端ClientChannelInitializer:

public class ClientChannelInitializer extends  ChannelInitializer<SocketChannel> {

    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();

        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());

        // 客户端的handler
        //先调用handler在ChannnelActive方法中调用fireChannelActive会激活handler1
        pipeline.addLast("handler", new HWClientHandler());
        pipeline.addLast("handler1", new BaseClientHandler());
    }
}
  •  

客户端handler:

public class HWClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("server say : "+msg.toString());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Handler1");
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Client is close");
    }
}
  •  

客户端的第二个handler:

public class BaseClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Handler2");
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}
  •  

服务端:

public class HWServer {
    private int port;

    public HWServer(int port) {
        this.port = port;
    }

    public void start(){
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();

        ServerBootstrap server = new ServerBootstrap().group(bossGroup,workGroup)
                                    .channel(NioServerSocketChannel.class)
                                    .childHandler(new ServerChannelInitializer());

        try {
            ChannelFuture future = server.bind(port).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        HWServer server = new HWServer(7788);
        server.start();
    }
}
  •  

服务端ServerChannelInitializer:

public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();

        // 字符串解码 和 编码
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());

        // 自己的逻辑Handler
        pipeline.addLast("handler", new HWServerHandler());
    }
}
  •  

服务端handler:

public class HWServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelActive");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress()+"===>server: "+msg.toString());
        ctx.write("received your msg");
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        ctx.close();
    }
}
  •  

我们启动服务端和客户端,会发现客户端的两个handler都通过了。 

先调用HWClientHandler,打印出:HWClientHandler channelActive;继而调用了BaseClientHandler ,打印出:BaseClient1Handler channelActive.

netty学习(三)springboot+netty+mybatis [TOC] 前言 前面写到了springboot整合netty,只是使用netty将数据处理了,还没有存入数据库,现在就把mybatis加进去吧;刚好最近也有一位读者问到了这个问题; 正文 首先引入pom依赖 &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; ... 阅读详情

相关推荐

Netty入门学习

打个比喻,每个 Channel 是一个产品的加工车间,Pipeline 是车间中的流水线,ChannelHandler 就是流水线上的各道工序,而后面要讲的 ByteBuf 是原材料,经过很多工序的加工:先经过一道道入站工序,再经过一道道出站工序最终变成产品。如果事件轮询的持续时间大于等于 timeoutMillis,那么说明是正常的,否则表明阻塞时间并未达到预期,可能触发了空轮询的 Bug,则计数器+1,如果计数器超过阙值,则重建Selector并迁移所有其管理的channel。如果还是没有则创建对象。

hsnsnusjs的博客 879

netty黑白名单RuleBasedIpFilter、同一个 IP 只能有一个连接UniqueIpFilter

根据netty中io.netty.handler.ipfilter包下实现。netty先建立链接之后通过pipeline中handler过滤cidr(无分类域)原理实现的

CodingAnHour 1474

netty学习笔记-01

netty学习笔记

weixin_45811645的博客 644

Netty入门学习笔记(一)

学习Netty前的知识了解,BIO、NIO、AIO、零拷贝,下一篇正式开始netty。

小楊同学的笔记本 1144

Netty4学习笔记(8)-- Channel接口

Channel是Netty4最核心的接口之一,拥有将近40个方法和一个内部接口。本文将对Channel接口的众多方法做一个归类和总结,为进一步研究Channel实现做准备。

zxh的专栏 9098

Netty札记-为什么要学习Netty

在学习Netty之前,有必要了解下我们为什么要学习Netty。 什么是Netty Netty User guide for 4.x中这样介绍 Netty是一个提供异步事件驱动的网络应用框架,是一个用以快速开发高性能、可扩展协议的服务器和客户端的工具。 换句话说,Netty 是一个 NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器和客户端的协议。Net

潘威威的博客 5466

(三)Netty之Channel通道

通道(Channel)基本介绍 NIO 的通道类似于流,但有些区别: 通道可以同时进行读写,而流只能读或者只能写 通道可以实现异步读写数据 通道可以从缓冲读数据,也可以写数据到缓冲 BIO中的stream是单向的,例如FileInputStream对象只能进行读取数据的操作,而NIO中的通道(Channel)是双向的,可以读操作,也可以写操作 Channel在NIO中是一个接口 public interface Channel extends Closeable{} 常见的Channel类有:F

qq_38949960的博客 1586

lumerical中DEVICE和MODE模块的交互使用(真的很干货!!可以自信的说网上绝对找不到比我更详细的步骤了)

几个脚本文件很重要! Lumerical仿真流程: 一、DEVICE: (1).建模并且运行完之后,在脚本提示符下键入以下脚本行以运行plotDopingProfile.lsf如图1(文件名如果索引不到的话就可以把文件直接用notepad++打开,然后把代码直接输入到device中script脚本中 如图2)脚本文件并生成下图 如图3: (图2) (图1) (图3) (2).仿真...

1万+

Netty源码分析之激活服务端通道

通道绑定活跃后激活管道的处理器 public final ChannelPipeline fireChannelActive() { AbstractChannelHandlerContext.invokeChannelActive(head); return this; } static void invokeChannelActive(final AbstractChan...

962

Flowable前端可视化配置动态审批人:告别硬编码,实现部门领导、项目经理自动分配

本文详细介绍了Flowable前端可视化配置动态审批人的全栈解决方案,通过表达式分配、监听器分配等动态审批人机制,实现从硬编码到智能分配的转变。文章提供了前端扩展bpmn-js设计器、后端动态解析实现方案及性能优化建议,帮助企业应对组织架构变动,提升审批流程的灵活性和效率。

weixin_30352645的博客 473

eNSP-交换机VLAN配置

VLAN

乌托托的博客 8809

Netty 入门学习

netty入门学习笔记; EventLoop,Channel,ByteBuf;

weixin_53142722的博客 4697

Windows 下 Claude Code 使用全记录:从零到一的保姆级图文教程(持续更新)

本文主要介绍了Windows 下 Claude Code 使用全记录:从零到一的保姆级图文教程,希望能对学习使用 Claude Code 的同学们有所帮助。 文章目录 1. 背景 2. 实战教程(2026年最新教程) 2.1 步骤一 Claude Code 环境准备 2.2 步骤二 配置Claude Code 2.3 步骤三 对话 3. 老版本实战教程 3.1 步骤一 配置Node.js 3.2 步骤二 Claude Code配置 3.3 步骤三 配置Claude Code 3.4 步骤四 对话

weixin_43178406的博客 15万+

Netty学习总结

1、虽然JAVA NIO 框架提供了多路复用IO 的支持,但是并没有提供上层“信息格式”的良好封装。例如前两者并没有提供针对Protocol Buffer、JSON 这些信息格式的封装,但是Netty 框架提供了这些数据格式封装(基于责任链模式的编码和解码功能);

qq_40228720的博客 1328

YOLO26训练自己的数据集,从代码下载到实例测试 (含YOLO26网络结构图)

在Windows10上配置CUDA环境教程2026年1月14日,YOLO26是最新发布的计算机视觉模型。支持多种任务,包括目标检测、实例分割、图像分类、姿态估计、有向目标检测以及物体跟踪等。以上就是YOLO26训练自己数据集的全部过程啦,欢迎大家在评论区交流~

Limiiiing的博客 6546

UG\NX二次开发 一个创建小平面体的例子

介绍。

王牌飞行员_里海的博客 445

Netty学习——Netty入门

二. Netty 入门 1. 概述 1.1 Netty 是什么? Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty 是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端。 这里的异步是指Netty采用了

maruofan666的博客 1985

MFC属性网格控件(CMFCPropertyGridCtrl)完全指南:构建专业属性编辑界面

本文详细介绍了MFC中的CMFCPropertyGridCtrl控件的使用方法。主要内容包括:控件基础用法(初始化、添加属性、事件处理)、高级设置(自定义外观、创建属性类型、动态更新)、派生类实现(自定义绘制、搜索过滤功能)、界面集成技巧(对话框布局、属性编辑器)以及实际应用示例。文章重点讲解了如何通过继承和自定义实现复杂功能,并提供了性能优化、多语言支持等最佳实践方案。该控件适用于需要大量参数配置的应用程序,能够创建类似Visual Studio属性窗口的专业界面。

专注现代C++实战,从核心语法到高性能编程,助力开发者深入掌握系统级编程精髓。 155

Netty 学习总结简介

Netty简介与总结

weixin_42222903的博客 1641

YOLO26 网络结构逐模块解析:Backbone/Neck/Head

本文解析了YOLO26目标检测网络的架构设计,重点介绍其在Backbone、Neck和Head三个核心组件的创新优化。Backbone采用改进的CSP模块与轻量级注意力机制,提升特征提取效率;Neck使用改进的BiFPN结构实现高效多尺度特征融合;Head采用完全解耦设计简化回归流程。文章详细分析了各模块的技术演进、实现细节和设计思想,通过流程图和代码示例展示了YOLO26的整体架构和关键组件实现。该研究对模型优化、定制开发和硬件部署具有重要指导意义。

一键难忘的博客 1248

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

初识Netty-Netty是什么和主要接口

netty

qq_44641527的博客 794

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Netty学习之NIO基础

Channel与BufferJava NIO系统的核心通道(Channel)和缓冲区(Buffer)。通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理简而言之,通道负责传输,缓冲区负责存储常见的Channel有以下四种,其中FileChannel主要用于文件传输,其余三种用于网络通信Buffer有以下几种,其中使用较多的是ByteBufferByteBuffer。

qq_29012499的博客 1453

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: Netty从零开始(一)
下一篇: Netty从零开始(二)
hxpjava1
博客等级 码龄19年 1365粉丝 511原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值