Netty framework implements a simple client-server communication case (with executable code in IDEA)

            First of all, make sure to introduce the netty jar package (netty version 4.1.20). I use Maven inside IDEA, because this way the jar package can be directly placed in the lib directory of the project, which is simple and convenient. Those who haven’t downloaded it can check out:

1. Open the Project Structure and click on the Modules module:

 

 2. Enter io.netty:netty-all and click the search button, remember to ensure that IDEA is connected to the Internet, and wait a while, after all, it will not display the search results at once, then select the 4.1.20 version to download, and compare the first download slow.

 

Attach the structure of the executable project in IDEA:

Not much to say, start to code! Because the necessary comments are already in the code, no other explanation will be given.

NettyServer.java

package simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        //创建两个线程组:BossGroup:处理连接请求和WorkerGroup:真正与客户端业务处理,两个都是无限循环
        EventLoopGroup BossGroup = new NioEventLoopGroup();
        EventLoopGroup WorkerGroup = new NioEventLoopGroup();

        try {
            //创建服务器端的启动对象,配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            //使用链式编程来进行设置
            bootstrap.group(BossGroup, WorkerGroup)//设置两个线程组
                    .channel(NioServerSocketChannel.class)//使用NIOSocketChannel作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128)//设置线程队列得到连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {//创建一个通道初始化对象(匿名对象)
                        //给pipline设置处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyServerHandler());
                        }
                    });//给我们EventGroup对应的管道设置处理器

            System.out.println("服务器is ready!");

            //绑定一个端口并同步,生成了一个ChannelFuture对象
            //启动服务器(并绑定端口)
            ChannelFuture channelFuture = bootstrap.bind(6668).sync();

            //对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
        }finally {
            BossGroup.shutdownGracefully();
            WorkerGroup.shutdownGracefully();
        }
    }
}

NettyServerHandler.java

package simple;

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;

import java.nio.charset.Charset;

//我们自定义一个handler需要继续netty规定好的某个HandlerAdapter(规范)
//这时我们制定的一个handler,才能称为一个handler

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    //这里我们可以读取客户端发送的消息
    /*
    1.ChannelHandlerContext ctx:上下文对象,含有管道pipline,通道channel,地址
    2.Object msg默认是客户端发送的消息,默认Object
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("server ctx=" +ctx);
        //将msg转成byteBuf
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("客户端发送消息是" + byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("客户端地址是:"+ ctx.channel().remoteAddress());
    }

    //数据读取完毕
    @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();
    }
}

 

-------------------------------------------------- -------Dividing line: The above is the server side, and then write the client side ------------------------------ ---------------------

NettyClient.java

package simple;

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;

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        try{
        //创建客户端启动对象,注意客户端使用的不是ServerBootStrap而是BootStrap
        Bootstrap bootstrap = new Bootstrap();
        //设置相关参数
        bootstrap
                .group(group)//设置线程组
                .channel(NioSocketChannel.class)//设置客户端通道的实现类
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new NettyClientHandler());
                    }
                });
        System.out.println("客户端OK");
        //启动客户端去连接服务器端
        //关于channel要分析,要分析netty的异步模型
        ChannelFuture channelfulture = bootstrap.connect("127.0.0.1", 6668).sync();
        channelfulture.channel().closeFuture().sync();
    }finally {
        group.shutdownGracefully();
        }
        }
}

NettyClientHandler.java

package simple;

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;

public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    //当通道就绪就会触发该方法
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("clinet" + ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello,Server",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();
    }
}

OK, then run the server first, and then run the client, you can see the console output information.

Server output:

Client output:

 

             Euler, it ends here. Friends who approve of this article, understand what I mean? Trouble Sanlian┗|`O′|┛ ~, like, follow, favorite~

Guess you like

Origin blog.csdn.net/Zhongtongyi/article/details/107642835