欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Netty入门 && 第一个Netty程序

程序员文章站 2022-03-23 21:59:44
1 为什么要用 Netty(1) 虽然 JAVA NIO 框架提供了 多路复用 IO 的支持,但是并没有提供上层“信息格式”的良好封装。例如前两者并没有提供针对 Protocol Buffer、JSON 这些信息格式的封装,但是Netty 框架提供了这些数据格式封装(基于责任链模式的编码和解码功能)。(2) NIO 的类库和 API 相当复杂,使用它来开发,需要非常熟练地掌握 Selector、ByteBuffer、ServerSocketChannel、SocketChannel 等,需要很多额外的编...

1 为什么要用 Netty

(1) 虽然 JAVA NIO 框架提供了 多路复用 IO 的支持,但是并没有提供上层“信息格式”的良好封装。例如前两者并没有提供针对 Protocol Buffer、JSON 这些信息格式的封装,但是Netty 框架提供了这些数据格式封装(基于责任链模式的编码和解码功能)。

(2) NIO 的类库和 API 相当复杂,使用它来开发,需要非常熟练地掌握 Selector、ByteBuffer、ServerSocketChannel、SocketChannel 等,需要很多额外的编程技能来辅助使用 NIO,例如,因为 NIO 涉及了 Reactor 线程模型,所以必须必须对多线程和网络编程非常熟悉才能写出高质量的 NIO 程序。

(3) 要编写一个可靠的、易维护的、高性能的 NIO 服务器应用。除了框架本身要兼容实现各类操作系统的实现外。更重要的是它应该还要处理很多上层特有服务,例如:客户端的权限、还有上面提到的信息格式封装、简单的数据读取,断连重连,半包读写,心跳等等,
这些 Netty 框架都提供了响应的支持。

2 Netty简介

2.1 EventLoop(Group) 、Channel

Channel 是 Java NIO 的一个基本构造。它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一
个或者多个不同的 I/O 操作的程序组件)的开放连接,如读操作和写操作。目前,可以把 Channel 看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。EventLoop 暂时可以看成一个线程、EventLoopGroup 自然就可以看成线程组。
Netty入门 && 第一个Netty程序

2.2 事件和 ChannelHandler、ChannelPipeline

Netty 使用不同的事件来通知我们状态的改变或者是操作的状态。这使得我们能够基于已经发生的事件来触发适当的动作。Netty 事件是按照它们与入站或出站数据流的相关性进行分类的。可能由入站数据或者相关的状态更改而触发的事件包括:连接已被激活或者连接失活;数据读取;用户事件;错误事件。

出站事件是未来将会触发的某个动作的操作结果,这些动作包括:打开或者关闭到远程节点的连接;将数据写到或者冲刷到套接字。每个事件都可以被分发给 ChannelHandler 类中的某个用户实现的方法。Netty 提供了大量预定义的可以开箱即用的 ChannelHandler 实现,包括用于各种协议(如 HTTP 和 SSL/TLS)的 ChannelHandler。
Netty入门 && 第一个Netty程序

3 第一个 Netty 程序

3.1 EchoServerHandler

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("Server accept: " + byteBuf.toString(CharsetUtil.UTF_8));
        ctx.writeAndFlush(byteBuf);
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

3.2 EchoServer

public class EchoServer {


    public static void main(String[] args) throws InterruptedException {

        //服务器启动
        ServerBootstrap bootstrap = new ServerBootstrap();
        //线程组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //配置启动器
            bootstrap.group(group)
                    //channel
                    .channel(NioServerSocketChannel.class)
                    //启动端口
                    .localAddress(new InetSocketAddress(8888))
                    //handler
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new EchoServerHandler());
                        }
                    });

            //绑定服务器,sync阻塞完成
            ChannelFuture channelFuture = bootstrap.bind().sync();
            System.out.println("EchoServer started");
            //阻塞线程知道服务器channel close
            channelFuture.channel().closeFuture().sync();
        } finally {
            //退出,释放线程池
            group.shutdownGracefully();
        }
    }


}

3.3 EchoClientHandler

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        System.out.println("client accept " + byteBuf.toString(CharsetUtil.UTF_8));
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8));
    }
}

3.4 EchoClient

public class EchoClient {

    public static void main(String[] args) {

        //客户端启动
        Bootstrap bootstrap = new Bootstrap();
        //线程组
        EventLoopGroup group = new NioEventLoopGroup();
        try {

            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress("127.0.0.1", 8888))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new EchoClientHandler());
                        }
                    });

            //等待链接完成
            ChannelFuture channelFuture = bootstrap.connect().sync();
            //阻塞当前线程,直到channel关闭
            channelFuture.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //退出,释放线程池
            group.shutdownGracefully();
        }

    }

}

3.5 测试结果

Netty入门 && 第一个Netty程序
Netty入门 && 第一个Netty程序

本文地址:https://blog.csdn.net/qq_34125999/article/details/110901170

相关标签: Netty