Netty simple introductory examples and some summary by debug

Every line of code has a comment, please watch carefully:

Client:

package com.jym.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @program: NettyPro
 * @description: Netty服务端练习
 * @author: jym
 * @create: 2020/02/07
 */
public class JymNettyServer {
    public static void main(String[] args) throws InterruptedException {
        // 创建bossGroup,workGroup
        // 1.创建两个线程组bossGroup和workGroup
        // 2.bossGroup只是处理连接请求,真正的和客户端处理,会交给workGroup完成
        // 3.两个都是无限循环
        // 4.bossGroup和workGroup还有的子线程(NioEventLoop)的个数,默认实际CPU的核数*2
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            // 创建服务器端启动的对象,可以配置启动参数
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            // 使用链式编程来进行设置
            // 设置两个线程组
            serverBootstrap.group(bossGroup,workGroup)
                    // 使用NioServerSocketChannel作为服务器的通道实现
                    .channel(NioServerSocketChannel.class)
                    // 设置线程队列得到连接个数
                    .option(ChannelOption.SO_BACKLOG,128)
                    // 设置保持活动连接状态
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    // 给我们的workGroup的EventLoop对应的管道设置处理器
                    // 创建一个通道测试对象
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        // 给pipeline设置处理区
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new JymNettyServerHandler());
                        }
                    });
            System.out.println("服务器 is ready");
            // 绑定端口并且同步,生成一个ChannelFuture对象,启动服务器
            ChannelFuture sync = serverBootstrap.bind(6668).sync();
            // 对关闭通道进行监听
            sync.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }


    }
}

The client handler

package com.jym.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/**
 * @program: NettyPro
 * @description: 1.自定义handler,需要继承netty规定好的某个HandlerAdapter(规范)
 * @description: 2.这时我们的自定义handler,才能称为一个handler
 * @author: jym
 * @create: 2020/02/08
 */
public class JymNettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     *  读取数据实际(这里我们可以读取从客户端发来的消息)
     *  1.ChannelHandlerContext ctx:上下文对象,含有管道pipeline,通道,地址
     *  2.Object msg: 客户端发送的数据,默认是object的形式
     */
    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("服务器读取线程:" + Thread.currentThread().getName());
        System.out.println("server ctx=" + ctx);
        // 将msg转成一个byteBuf,是netty提供的 不是nio的
        ByteBuf byteBuf = (ByteBuf)msg;
        System.out.println("客户端发送的消息是:" + byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("客户端地址为:" + ctx.channel().remoteAddress().toString());
    }

    /**
     * 数据读取完毕
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // writeAndFlush 是write+flush,将数据写入到缓存,并刷新
        // 一般讲,我们对发送的数据进行一个编码
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端",CharsetUtil.UTF_8));
    }

    /**
     * 处理异常,一般是关闭连接
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

Server

package com.jym.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @program: NettyPro
 * @description: Netty客户端练习
 * @author: jym
 * @create: 2020/02/08
 */
public class JymNettyClient {
    public static void main(String[] args) throws InterruptedException {
        // 客户端需要一个事件循环组
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            // 创建客户端启动对象,注意:客户端使用的不是SeverBootstrap,而是Bootstrap
            Bootstrap bootstrap = new Bootstrap();

            // 设置相关参数
            // 设置线程组
            bootstrap.group(group)
                    // 设置通道的实现类(反射)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 加入自己的处理器
                            socketChannel.pipeline().addLast(new JymNettyClientHandler());
                        }
                    });
            System.out.println("客户端 is ok");

            // 启动客户端去连接服务器端
            // 关于 ChannelFuture 要分析,涉及到netty的异步模型
            ChannelFuture sync = bootstrap.connect("127.0.0.1", 6668).sync();
            // 给关闭通道进行监听
            sync.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }

    }
}

Server handler

package com.jym.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/**
 * @program: NettyPro
 * @description: 处理器
 * @author: jym
 * @create: 2020/02/08
 */
public class JymNettyClientHandler extends ChannelInboundHandlerAdapter {
    /**
     * 通道就绪就会触发该方法
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client :" + ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,server ~o( =∩ω∩= )m", CharsetUtil.UTF_8));
    }

    /**
     * 通道有读取时间时触发
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("服务器回复的消息:"+ byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("服务器的地址:" + ctx.channel().remoteAddress());
    }

    /**
     * 处理异常,关闭上下文
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
Test Results:

Server:
Here Insert Picture Description
Client (two):
Here Insert Picture Description
Here Insert Picture Description

to sum up:

1. Print can be seen, ChannelHandlerContext each connection object is obtained is different, so each of Channel (pipe) and Pipeline (channel) is different depending on the client console
2.bossGroup workGroup with two thread group, you can specify the number of threads in the constructor, if the number is not specified, the default number of nuclei for the CPU * 2 (if cpu server quad-core, the number of threads 8)
3.sync.channel (). closeFuture () .sync () is not closed, but to be closed for a listener
4. we processor ChannelHandlerContext object can get most of the object, which is a context object
5. each time a client and server connection, server thread is not the same
6.ChannelHandlerContext can get to the channel and pipeline, and that you have me, I have you in relationship

        System.out.println("===========channel和pipeline的关系=============");
        Channel channel = ctx.channel();
        ChannelPipeline pipeline1 = channel.pipeline();
        // 本质是一个双向链表,出栈入栈问题
        ChannelPipeline pipeline = ctx.pipeline();
        Channel channel1 = pipeline.channel();
        System.out.println("pipeline1里的channel与ctx里的channel是否为同一个对象:"+ (channel==channel1));
        System.out.println("channel里的pipeline1与ctx里的pipeline是否为同一个对象:"+ (pipeline1==pipeline));
        System.out.println("==============================================");

The output is:

true
true

Lack of study time, too shallow knowledge, that's wrong, please forgive me.

There are 10 kinds of people in the world, one is to understand binary, one is do not understand binary.

Published 71 original articles · won praise 54 · views 420 000 +

Guess you like

Origin blog.csdn.net/weixin_43326401/article/details/104228476