netty入门,入门代码执行流程,netty主要组件的理解

入门

netty底层采用多路复用技术,是异步的。底层也是采用的NIO。

入门代码

要使用netty,第一步当然是导入坐标

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.39.Final</version>
</dependency>

然后创建服务器端的代码

package com.hs.nettyPrimary;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

/**
 1. netty入门,服务器端代码
 2. @author hs
 3. @date 2021/07/16
 */
public class HelloServer {
    public static void main(String[] args) {
        // 服务器端的启动器  负责组装netty的组件 并协调它们工作
        new ServerBootstrap()
             // 添加一个EventLoop组 一个Selector+Thread = EventLoop  loop循环 event事件 也就是循环处理事件  group组
                .group(new NioEventLoopGroup())
                // 选择服务器的ServerSocketChannel实现
                .channel(NioServerSocketChannel.class)
         // child就相当于之前处理read事件的worker  childHandler()方法的作用就是决定了child能干什么事情
         // 方法的参数 ChannelInitializer 就代表跟客户端进行读写的通道 它其实也是一个handler 它的作用的加载其他的handler
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                // 添加具体的handler   StringDecoder 解码 因为传输都是用的ByteBuffer 这里是将ByteBuffer转换为String
                        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);
                            }
                        });
                    }
                })
                // 端口
                .bind(8080);
    }
}

服务端的大致流程就是:

  1. 创建一个ServerBootstrap() 服务器的启动器
  2. 添加NioEventloopGroup组
  3. 选择ServerSocketChannel的实现
  4. 添加child的处理器,这里仅仅是添加,执行会在客户端连接服务器后执行
  5. 绑定端口

客户端的代码和服务器端很相似

package com.hs.nettyPrimary;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * @author hs
 * @date 2021/07/17
 */
public class HelloClient {
    public static void main(String[] args) throws InterruptedException {
        // 这里也是先创建一个启动器,这是客户端的启动器,注意导包不要导错了
        new Bootstrap()
                // 这是添加EventLoop的作用主要是体现在服务器端,因为服务器要开多个线程充当boss和worker
                .group(new NioEventLoopGroup())
                // 选择客户端SocketChannel的实现
                .channel(NioSocketChannel.class)
                // 添加处理器,下面的方法会在客户端与服务器端连接成功后调用,会调用initChannel()方法
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel socketChannel) throws Exception {
                        // 服务器那边要接收数据,接收的是字节 就需要使用decoder来编码
                        // 而客户端这边是发送的字符串,要编码成字节发送,所以这里是使用encoder
                        socketChannel.pipeline().addLast(new StringEncoder());
                    }
                })
                // 连接服务器
                .connect("localhost",8080)
            	// 阻塞方法,直到客户端与服务器端连接建立后才会往下执行
                .sync()
            	// 代表的客户端与服务器之间数据传输的SocketChannel,netty对它做了封装 
                .channel()
                // 发送数据
                .writeAndFlush("hello,netty!");
    }
}

这时候服务器与客户端都启动后,客户端就会在连接服务器成功后往服务器发送一个"hello,netty!" 的消息,首先会经过客户端的Handler将字符串编码为字节数组进行传输,服务器端刚开始接受的也是字节数组,服务器端的Handler会先将字节数组解码为字符串,然后再由下一个Handler进行处理,也就是我们自定义的输出语句。具体的执行流程如下。


执行流程

  • 添加Handel处理器时,仅仅只是添加,还没有执行,需要等到客户端与服务器端连接成功后才会调用initChannel()初始化处理器,等到读写事件发生了就执行相应的处理器

  • 事件发生都会先到EventLoop这里,然后在由Handel处理器来进行实际的处理

  • 收发数据都会经过处理器

在这里插入图片描述

主要组件的理解

  • 服务器端msg:可以理解为流动的数据,服务器这边首先接收的是ByteBuf,然后在经过多个pipeline的处理加工,会变成其他类型的对象

  • channel:数据的通道

  • handler理解为处理数据的工序,工序有多个,合在一起就是pipeline(流水线)。pipeline负责发布事件,传播给每个handler,handler再对自己感兴趣的事情进行处理(在自定义handler中重写了相应的事件处理方法)

    handler分为两类:Inbound和Outbound 也就是入站和出站

  • EventLoop:处理数据的工人,因为EventLoop有一个线程,真正做事的也就是这个线程

    • 工人可以管理多个channel的io操作,并且一个工人如果选择了一个channel就要负责到底(绑定) ,这里主要也只是绑定io操作
    • 工人即可以执行io操作,也可以进行任务处理,每位工人有任务队列,队列里可以堆放多个channel待处理的任务,任务可以分为普通任务和定时任务
    • 工人按照pipeline顺序,依次按照handler的规则(代码)处理数据,对于非io操作的工序可以为指定不同的工人

总之,meg是数据,channel的传输数据的通道,handler是处理数据的工序,多个工序合在一起就是pipeline,EventLoop是处理数据的工人。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值