netty-demo-入门程序

Netty入门

一、目标

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

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

引入依赖

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

二、实现代码

2.1 服务器端
package org.example.netty.one;

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;
import lombok.extern.slf4j.Slf4j;

/**
 * 目标 :客户端像服务端发送Hello World
 *       服务端仅接受,不返回
 */
@Slf4j
public class Server {
    public static void main(String[] args) {
        //负责处理TCP/IP连接的
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        // 负责处理Channel(通道)I/O事件的  可以配置多个线程  有默认线程
        NioEventLoopGroup workGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap()
                // 分配boss worker
                .group(bossGroup, workGroup)
                //选择Socket实现类
                /**
                 * EpollServerSocketChannel
                 */
                .channel(NioServerSocketChannel.class)
                /**
                 * 下面添加的处理器都是给SocketChannel用的而不是给ServerSocketChannel,
                 * ChannelInitializer处理器只执行一次,作用:待客户端SocketChannel建立连接后,执行InitChannel以便添加更多的处理器
                 *
                 */
                //boss负责处理连接 worker(child) 负责处理读写,决定了 worker(child) 能执行哪些操作(handler)
                .childHandler(
                        //channel 代表和客户端进行数据读写的通道 Initializer 初始化,初始channel通道
                        //本身也是一个handler,负责添加别的handler 在创建时只是添加了初始化器,并未执行初始化器的内容,
                        //也就是initChannel方法,创建了连接后才执行的初始化器的初始化方法
                        new ChannelInitializer<NioSocketChannel>() {
                            //在连接建立后被初始化
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        // client接收到消息后 先出处理这里面的handler
                        // SocketChannel的解码器 解码ByteBuf => String
                        //在连接建立后的初始化时会执行addLast()方法,但是不会执行处理器,处理器是在收发数据时才执行
                        nioSocketChannel.pipeline().addLast(new StringDecoder());

                        nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            // SocketChannel 业务处理器使用上一个处理器的处理结果
                            //触发了读事件以后要执行的操作
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                log.debug("msg:{}", msg);
                            }
                        });
                    }
                });
                // 绑定ServerSocketChannel监听的端口
        serverBootstrap.bind(9999);
    }
}

2.2 客户端
package org.example.netty.one;

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


public class Client {
    public static void main(String[] args) throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        // 创建NioEventLoopGroup 与server端类似
        bootstrap.group(new NioEventLoopGroup())
                // 选择NioSocketChannel 作为Socket实现类
                .channel(NioSocketChannel.class)

                .handler(new ChannelInitializer<NioSocketChannel>() {
                    /**
                     * 连接的时候执行一次
                     * 作用 : 建立连接以后执行 initChannel 以便添加更多的处理器
                     *
                     * @param nioSocketChannel
                     * @throws Exception
                     */
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        // 消息会经过通道handler处理, 将String => ByteBuf 最后发出
                        //数据经过网络传输,到达服务器端,服务器端  的 handler 先后被触发,走完一个流程
                        nioSocketChannel.pipeline().addLast(new StringEncoder());
                    }
                });
        // 指定连接要连接的服务器地址以及端口
        ChannelFuture future = bootstrap.connect("127.0.0.1", 9999);
        // connect 是异步的 返回的是Future  所以需要通过sync 阻塞等待连接 还可以通过其他方式
        future.sync();
        // 写入消息并清空缓冲区
        future.channel().writeAndFlush("Hello World");


    }
}

2.3 流程梳理

在这里插入图片描述

提示

一开始需要树立正确的观念

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值