Netty 详细讲解,附服务端,客户端代码例子

  1. 服务器启动代码(SimpleServer.java)

    • EventLoopGroup 的作用是管理事件循环组,它们负责处理不同类型的事件,如接受传入连接、读取/写入数据等。在这里,我们创建了两个 EventLoopGroupbossGroupworkerGroupbossGroup 用于接受传入的连接请求,而 workerGroup 则用于实际处理连接的流量。

    • ServerBootstrap 是 Netty 用于启动服务器的帮助类。通过 group() 方法将两个 EventLoopGroup 绑定到服务器上。

    • channel() 方法指定了服务器使用的通道类型。在这里,我们选择了 NioServerSocketChannel.class,这意味着我们将使用基于 NIO 的 Socket 通道。

    • childHandler() 方法设置了一个 ChannelInitializer,当一个新的连接被接受时,这个初始化器将会被调用。在这里,我们为新连接的通道添加了一个处理器,即 SimpleServerHandler

    • 最后,我们通过 bind() 方法绑定了服务器端口,并调用 sync() 方法来阻塞,直到服务器关闭。这确保了服务器在启动后保持运行。
       

      TCP 服务器示例

      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;
      
      public class SimpleServer {
          public static void main(String[] args) throws InterruptedException {
              // 创建两个 EventLoopGroup,用于处理连接和处理数据
              EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 处理连接的线程组
              EventLoopGroup workerGroup = new NioEventLoopGroup(); // 处理数据的线程组
      
              try {
                  // 创建 ServerBootstrap 对象来启动服务器
                  ServerBootstrap serverBootstrap = new ServerBootstrap();
                  serverBootstrap.group(bossGroup, workerGroup)
                          .channel(NioServerSocketChannel.class) // 使用 NIO 通道
                          .childHandler(new ChannelInitializer<SocketChannel>() {
                              @Override
                              protected void initChannel(SocketChannel ch) throws Exception {
                                  // 添加处理器到管道中
                                  ch.pipeline().addLast(new SimpleServerHandler());
                              }
                          });
      
                  // 绑定端口并启动服务器
                  ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
                  channelFuture.channel().closeFuture().sync();
              } finally {
                  // 优雅关闭线程组
                  bossGroup.shutdownGracefully();
                  workerGroup.shutdownGracefully();
              }
          }
      }
      

  2. 服务器处理器(SimpleServerHandler.java)

    • SimpleServerHandler 是一个自定义的 ChannelInboundHandlerAdapter 的子类,用于处理从客户端接收到的消息。

    • 当有数据从客户端传入时,channelRead() 方法将会被调用。在这里,我们将传入的消息转换为 ByteBuf 对象,并在控制台上打印其内容。

    • 如果发生异常,exceptionCaught() 方法将被调用,我们在这里简单地打印异常信息并关闭连接。这是一种良好的做法,以确保服务器在出现问题时能够优雅地关闭连接并释放资源。

      服务器处理器示例:

      import io.netty.buffer.ByteBuf;
      import io.netty.channel.ChannelHandlerContext;
      import io.netty.channel.ChannelInboundHandlerAdapter;
      
      public class SimpleServerHandler extends ChannelInboundHandlerAdapter {
          @Override
          public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
              // 读取客户端发送的消息
              ByteBuf buf = (ByteBuf) msg;
              try {
                  while (buf.isReadable()) {
                      // 输出消息内容到控制台
                      System.out.print((char) buf.readByte());
                      System.out.flush();
                  }
              } finally {
                  // 释放资源
                  buf.release();
              }
          }
      
          @Override
          public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
              // 异常处理
              cause.printStackTrace();
              ctx.close();
          }
      }
      

  3. 客户端启动代码(SimpleClient.java)

    • 与服务器端启动代码类似,我们也需要一个 EventLoopGroup 来处理客户端连接。在这里,我们只需要一个 EventLoopGroup

    • Bootstrap 是用于启动客户端的帮助类。我们通过 group() 方法将 EventLoopGroup 绑定到客户端上。

    • channel() 方法指定了客户端使用的通道类型。在这里,我们同样选择了基于 NIO 的 Socket 通道。

    • handler() 方法设置了一个 ChannelInitializer,用于在连接建立时配置新的通道。在这里,我们添加了一个 SimpleClientHandler 来处理客户端的连接。

    • 最后,我们通过 connect() 方法连接到服务器,并调用 sync() 方法来阻塞,直到连接关闭。这确保了客户端在连接建立后保持运行。

       

      TCP 客户端示例

      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 SimpleClient {
          public static void main(String[] args) throws InterruptedException {
              // 创建一个 EventLoopGroup 用于处理连接
              EventLoopGroup group = new NioEventLoopGroup();
      
              try {
                  // 创建 Bootstrap 对象来启动客户端
                  Bootstrap bootstrap = new Bootstrap();
                  bootstrap.group(group)
                          .channel(NioSocketChannel.class) // 使用 NIO 通道
                          .handler(new ChannelInitializer<SocketChannel>() {
                              @Override
                              protected void initChannel(SocketChannel ch) throws Exception {
                                  // 添加处理器到管道中
                                  ch.pipeline().addLast(new SimpleClientHandler());
                              }
                          });
      
                  // 连接到服务器
                  ChannelFuture channelFuture = bootstrap.connect("localhost", 8888).sync();
                  // 阻塞直到连接关闭
                  channelFuture.channel().closeFuture().sync();
              } finally {
                  // 优雅关闭线程组
                  group.shutdownGracefully();
              }
          }
      }
      

  4. 客户端处理器(SimpleClientHandler.java)

    • SimpleClientHandler 同样是一个自定义的 ChannelInboundHandlerAdapter 的子类,用于处理从服务器接收到的响应消息。

    • 当连接建立并且数据可读时,channelRead() 方法将会被调用。在这里,我们将从服务器接收到的消息转换为 ByteBuf 对象,并在控制台上打印其内容。

  5. 如果发生异常,exceptionCaught() 方法将被调用,我们在这里简单地打印异常信息并关闭连接。这也是一种良好的做法,以确保客户端在出现问题时能够优雅地关闭连接并释放资源。

     

    客户端处理器示例:

    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    
    public class SimpleClientHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            // 当连接建立时发送消息到服务器
            ByteBuf buf = ctx.alloc().buffer();
            buf.writeBytes("Hello from client".getBytes());
            ctx.writeAndFlush(buf);
        }
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            // 读取服务器发送的消息并输出到控制台
            ByteBuf buf = (ByteBuf) msg;
            try {
                while (buf.isReadable()) {
                    System.out.print((char) buf.readByte());
                    System.out.flush();
                }
            } finally {
                buf.release();
            }
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            // 异常处理
            cause.printStackTrace();
            ctx.close();
        }
    }
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值