Netty【二】 第一个Netty应用

前言

上一篇中简单介绍了 NIO ,也演示了一个 NIO 的Demo,我们可以看出 NIO 的编程相对来说比较麻烦,必须对 API 很熟悉才行,而 Netty 框架相对于原生的 NIO 来说它的API 使用是比较简单的,并且功能强大,内置了多种编解码功能,支持多种主流协议,修复了已经发现的所有JDK API BUG等。接下来我们用 Netty 框架来实现上一篇的 Demo。

Demo

  • 环境
    本文所使用的 Netty 版本 4.1.18.Final, 在 pom.xml 添加如下代码或者点击下载
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.18.Final</version>
        </dependency>
  • 代码分析
    一、服务端
    (一)DemoServerHandler
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;

/**
 * Created by dzb on 2017/12/17.
 * 该 Demo 只需要用到少量方法,所以继承 ChannelInboundHandlerAdapter 就可以了,
 *  它提供了ChannelInboundHandler的默认实现
 */
public class DemoServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * 每传入一次消息都要调用这个方法
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("服务端收到客户端传来的消息是:" + buf.toString(CharsetUtil.UTF_8));
        /**
         *  将数据写到 Channel 中,等到操作结束再刷新发送出去
         */
        ctx.write(Unpooled.copiedBuffer("Hello Client".getBytes()));
    }
    /**
     * 当前操作的最后一条消息读取后调用,也就是说一次操作可能多条消息
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // 刷新发送数据
        ctx.flush();
    }

    /**
     * 读取操作期间发生异常调用的
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        // 关闭 Channel
        ctx.close();
    }
}

(二)DemoServer

import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;


/**
 * Created by dzb on 2017/12/17.
 */
public class DemoServer{
    private static int port = 8080;

    public static void main(String[] args) {
        // 创建 NIO 线程组,这里创建两个的原因是
        // 一个用于服务端接收客户端的连接,另外一个用于进行 SocketChannel 的网络读写
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            // NIO 服务端的辅助启动类
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workGroup)
                    // 设置Channel为NioServerSocketChannel,功能对应着NIO的ServerSocketChannel类
                    .channel(NioServerSocketChannel.class)
                    // 绑定处理类
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) throws Exception {
                           ch.pipeline().addLast(new DemoServerHandler());
                        }
                    });
            // 绑定端口, 同步等待成功
            ChannelFuture f = b.bind(port).sync();
            // 等待服务端监听端口关闭
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            // 释放所有资源
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}

二、客户端
(一)DemoClientHandler

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

/**
 * Created by dzb on 2017/12/17.
 */
public class DemoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    /**
     * 与服务器建立连接后调用
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 发送数据
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Server", CharsetUtil.UTF_8));
    }

    /**
     * 接受到消息时调用
     * @param ctx
     * @param msg
     * @throws Exception
     */
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("收到服务端的信息:" + msg.toString(CharsetUtil.UTF_8));
    }

    /**
     * 发生异常时调用
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        ctx.close();
    }
}

(二)DemoClient

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;


/**
 * Created by dzb on 2017/12/17.
 */
public class DemoClient {
    private static int port = 8080;
    private static String host = "127.0.0.1";

    public static void main(String[] args) {
        // 创建线程组
        EventLoopGroup group = new NioEventLoopGroup();
        // 创建客户端的启动
        try {
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new DemoClientHandler());
                        }
                    });
            // 发起异步连接操作
            ChannelFuture f = b.connect(host, port).sync();
            // 等待客户端链路关闭
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
            group.shutdownGracefully();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36712034/article/details/78828825