Netty学习(二)-- 概述和初体验

目录

      • 1、概述
        • 1.1、什么是 Netty?
        • 1.3、Netty 的地位
        • 1.4、Netty 的优势
      • 2、Hello World
        • 2.1、初体验
        • 2.2、导入依赖
        • 2.3、服务器端代码
        • 2.4、客服端代码
        • 2.5、执行流程图
        • 2.6、一些理解

1、概述

1.1、什么是 Netty?

Netty 是由 Trustin Lee 提供的一个 Java 开源框架,现为 GitHub 上的独立项目。Netty 是一个基于 NIO 的客户、服务器端的编程框架。

Netty 是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端。

1.3、Netty 的地位

Netty 在 Java 网络应用框架中的地位就好比:Spring 框架在 JavaEE 开发中的地位。

以下框架都是用了 Netty ,它们都有网络通信需求!

  • Cassandra - NoSQL 数据库
  • Spark - 大数据分布式计算框架
  • Hadoop - 大数据分布式存储框架
  • RockMQ - 阿里开源的消息队列
  • ElasticSearch - 搜索引擎
  • gRPC - rpc 框架
  • Dubbo - rpc 框架
  • Spring 5.x - Fulx api 完全抛弃了 Tomcat,使用 Netty 作为服务端
  • Zookeeper - 分布式协调框架

1.4、Netty 的优势

  • Netty 对比 NIO(工作量大,BUG多)
    • 需要自己构建协议
    • 解决 TCP 传输问题,如黏包、半包
    • epoll 空轮询导致 CPU 100%
    • 对 API 进行增强,使之更易使用。如 FastThreadLocal => ThreadLocal、ByteBuf=>ByteBuffer。
  • Netty 对比 其他网络应用框架
    • Mina 由 Apache 维护。Netty API 更简洁,文档更优秀。

2、Hello World

2.1、初体验

开发一个简单的服务器和客户端

  • 客户端向服务器发送 hello,world
  • 服务器仅接收,不返回

2.2、导入依赖

1、netty 依赖

<dependency>
  <groupId>io.nettygroupId>
  <artifactId>netty-allartifactId>
  <version>4.0.42.Finalversion>
dependency>

2、日志依赖:

 
<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <version>1.18.12version>
dependency>

<dependency>
    <groupId>org.slf4jgroupId>
    <artifactId>slf4j-apiartifactId>
    <version>1.7.7version>
dependency>

<dependency>
    <groupId>org.apache.logging.log4jgroupId>
    <artifactId>log4j-slf4j-implartifactId>
    <version>2.9.1version>
dependency>

3、log4j2.xml 文件配置





<configuration status="INFO" monitorInterval="30">
    
    <appenders>
        
        <console name="Console" target="SYSTEM_OUT">
                
            	
                <PatternLayout pattern="%date{HH:mm:ss} [%-5level] [%thread] %logger{17} - %m%n"/>
        console>

        

        <RollingFile name="logfile" fileName="G:/Typora/Netty/Netty/logs/system.log" filePattern="G:/Typora/Netty/Netty/logs/$${date:yyyy-MM}/system-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="%date{HH:mm:ss} [%-5level] [%thread] %logger{17} - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="50 MB"/>
            Policies>
            
            <DefaultRolloverStrategy compressionLevel="0" max="10"/>
        RollingFile>
    appenders>

    
	
    <loggers>
        
        <logger name="com.example" level="DEBUG" additivity="false">
            <appender-ref ref="Console" />
        logger>
        <root level="ERROR">
            <appender-ref ref="Console" />
        root>
    loggers>
configuration>

2.3、服务器端代码

public class HelloServer {
    public static void main(String[] args) {
        // 1、服务端启动器,负责组装 netty 组件,启动服务器
        new ServerBootstrap()
                // 2、BossEventLoop WorkerEventLoop(包含selector, Thread), group 组
                .group(new NioEventLoopGroup())
                // 3、选择 服务器的 ServerSocketChannel 实现 (EpollServerSocketChannel、OioServerSocketChannel)
                .channel(NioServerSocketChannel.class)
                // 4、boss负责处理连接 worker(child)负责处理读写。决定 worker(child) 能执行哪些操作(handler)
                .childHandler(
                        // 5、Channel 代表和客户端进行数据读写的通道;Initializer 初始化,负责添加别的 handler
                    new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        // 6、添加具体的 handler
                        // 将 ByteBuf 转换为字符串
                        nioSocketChannel.pipeline().addLast(new StringDecoder());
                        // 自定义 handler
                        nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            @Override   // 读事件
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                // 打印上一步转换好的字符串
                                System.out.println(msg);
                            }
                        });
                    }
                })
                // 7、绑定监听端口
                .bind(8888);
    }
}

2.4、客服端代码

public class HelloClient {
    public static void main(String[] args) throws InterruptedException {
        // 1、客户端启动器
        new Bootstrap()
                // 2、添加 EventLoop
                .group(new NioEventLoopGroup())
                // 3、选择客户端 Channel 事件
                .channel(NioSocketChannel.class)
                // 4、添加处理器,
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override   // 连接建立后被调用
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringEncoder());
                    }
                })
                // 5、连接到服务器
                .connect(new InetSocketAddress("localhost", 8888))
                .sync()
                .channel()
                // 6、向服务器发送数据
                .writeAndFlush("hello, world");
    }
}

2.5、执行流程图

Netty学习(二)-- 概述和初体验_第1张图片

2.6、一些理解

  • 把 Channel 理解为数据的通道。
  • 把 msg 理解为流动的数据,最开始输入 ByteBuf,但经过 pipeline(流水线) 的加工,会变成其他类型对象,最后输出又变成 ByteBuf。
  • 把 handler 理解为数据处理的处理工序
    • 工序有多道,合在一起就是 pipeline(流水线),pipeline 负责发布事件(读、读取完成…)传播给每个 handler,handler 对自己感兴趣的事件进行处理(重写了相应事件处理方法)
    • handler 分 Inbound(入站) 和 Outbound(出站) 两类
  • 把 EventLoop 理解为处理数据的工人
    • 工人可以管理多个 Channel 的 IO 操作,并且一旦工人负责了某个 Channel,就要负责到底(绑定)。
    • 工人既可以执行 IO 操作,也可以进行任务处理,每位工人有任务队列,队列里可以堆放多个 Channel 的待处理任务,任务分为普通任务、定时任务。
    • 工人按照 pipeline 顺序,依次按照 handler 的规则(代码)处理数据。可以为每道工序指定不同的工人(非 IO 操作)。

你可能感兴趣的:(Netty,java,netty)