netty 第一款Netty应用程序

本文详细介绍如何使用Netty框架创建第一个HelloWorld服务,包括项目搭建、依赖引入、服务器与客户端代码实现,以及核心组件如ServerBootstrap、EventLoopGroup、ChannelInitializer等的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

netty 第一款Netty应用程序

  1. 创建项目
mvn archetype:generate  -DgroupId=org.xtxg -DartifactId=netty-frame-helloworld-server
  1. 引入pom
  <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.23.Final</version>
    </dependency>

3.编写Server引导类

  1. 引导过程步骤如下
    1. 创建一个ServerBootstrap的实例以引导和绑定服务器;
    2. 创建并分配一个NioEventLoopGroup实例以进行事件的处理,如接受新连接以及读/写数据;
    3. 指定服务器绑定的本地的InetSocketAddress;
    4. 使用一个EchoServerHandler的实例初始化每一个新的Channel;
    5. 调用ServerBootstrap.bind()方法以绑定服务器。
  2. ChannelHandler和业务逻辑
    因为你的Echo服务器会响应传入的消息,所以它需要实现ChannelInboundHandler接口,用来定义响应入站事件的方法。这个简单的应用程序只需要用到少量的这些方法,所以继承Channel-InboundHandlerAdapter类也就足够了,它提供了ChannelInboundHandler的默认实现。
  • 我们感兴趣的方法是:
  1. channelRead()——对于每个传入的消息都要调用;
  2. channelReadComplete()——通知ChannelInboundHandler最后一次对channelRead()的调用是当前批量读取中的最后一条消息;
  3. exceptionCaught()——在读取操作期间,有异常抛出时会调用
    代码如下
    EventLoopGroup group = new NioEventLoopGroup(); // 1.创建EventLoopGroup对象
            try {
                ServerBootstrap bootstrap = new ServerBootstrap(); // 2.创建BootStrap
                bootstrap.group(group)
                        .channel(NioServerSocketChannel.class) // 3.指定NIO方式传输Channel
                        .localAddress(new InetSocketAddress(port)) // 4.使用指定的端口设置套接字地址
                        .childHandler(new ChannelInitializer<SocketChannel>() { // 添加一个EchoServerHandle到Channel的ChannelPipline
    
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() { // 因为你的Echo服务器会响应传入的消息,所以它需要实现ChannelInboundHandler接口,用来定义响应入站事件的方法。这个简单的应用程序只需要用到少量的这些方法,所以继承Channel-InboundHandlerAdapter类也就足够了,它提供了ChannelInboundHandler的默认实现
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                        ByteBuf in = (ByteBuf) msg;
                                        System.out.println("服务端接收到信息 " + in.toString(CharsetUtil.UTF_8));// 将消息记录到控制台
    
                                        ctx.write(in); // 将接受到信息写个发送者,而不冲刷出站消息
                                    }
    
                                    @Override
                                    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
                                        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
    //                                            .addListener(ChannelFutureListener.CLOSE);// 将未决信息冲刷至远程节点,并且关闭Channel
                                    }
    
                                    @Override
                                    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                        cause.printStackTrace();// d打印异常栈
                                        ctx.close();// 关闭Channel
                                    }
                                });
                            }
                        });
                ChannelFuture future = bootstrap.bind().sync();// 6.异步绑定服务器;调用sync()方法阻塞等待直到绑定完成
                future.channel().closeFuture().sync();// 7.获取Channel的CloseFuture,并且阻塞当前线程直到它完成
            } finally {
                group.shutdownGracefully().sync(); // 8.关闭EventGroup,释放所有的资源
            }

4.编写client类
1.编写client引导类

 1. 为初始化客户端,创建了一个Bootstrap实例;  
2. 为进行事件处理分配了一个NioEventLoopGroup实例,其中事件处理包括创建新的连接以及处理入站和出站数据;
3. 为服务器连接创建了一个InetSocketAddress实例;
4. 当连接被建立时,一个EchoClientHandler实例会被安装到(该Channel的)ChannelPipeline中;
5. 在一切都设置完成后,调用Bootstrap.connect()方法连接到远程节点;
  1. 编写ChannelHandler实现客户端逻辑
    扩展SimpleChannelInboundHandler类以处理所有必须的任务,要求重写下面的方法
    1. channelActive()——在到服务器的连接已经建立之后将被调用;
    2. channelRead0()[5]——当从服务器接收到一条消息时被调用;
    3. exceptionCaught()——在处理过程中引发异常时被调用。
  2. 代码如下
EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host, port))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    ctx.writeAndFlush(Unpooled.copiedBuffer("你好,世界!", CharsetUtil.UTF_8));// 当被通知Channel是活跃的时候,发送一条消息
                                }

                                @Override
                                protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
                                    System.out.println("客户端收到:" + byteBuf.toString(CharsetUtil.UTF_8)); // 接收消息转储
                                    Thread.sleep(1000);
                                    byteBuf.retain();
                                    channelHandlerContext.writeAndFlush(byteBuf);
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 发生异常时,记录错误并关闭
                                    cause.printStackTrace();
                                    ctx.close();
                                }
                            });
                        }
                    });
            ChannelFuture future = bootstrap.connect().sync();// 连接到远程节点,阻塞等待直到连接完成
            future.channel().closeFuture().sync();// 阻塞,直到Channel关闭
        } finally {
            group.shutdownGracefully().sync();
        }

本章节详细代码,见 netty-frame-helloworld-server模块:https://gitee.com/gtxg/netty-learn.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值