Netty实践-- echo

Netty实践

学习netty,可以从netty源码的 netty-example 模块开始。

netty-example 有一个例子 echo,非常适合入门学习。

这里稍微改造一下,用作示例学习。

引入依赖包:

复制代码
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.29.Final</version>
        </dependency>

服务端

服务端收到客户端的消息后,会进行响应。

  • EchoServer:

    /**

    • 服务端收到客户端的消息后,会进行响应。
      /
      public final class EchoServer {
      /
      *

      • 端口
        */
        static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));

      public static void main(String[] args) throws Exception {
      // 配置 EventLoopGroup
      // 主从 Reactor 多线程模式,bossGroup是 主 Reactor,workerGroup是 从Reactor
      EventLoopGroup bossGroup = new NioEventLoopGroup(1);
      EventLoopGroup workerGroup = new NioEventLoopGroup();
      try {
      //初始化服务器的引导类 ServerBootstrap
      ServerBootstrap serverBootstrap = new ServerBootstrap();
      //指定 EventLoopGroup
      serverBootstrap.group(bossGroup, workerGroup)
      //指定 channel
      .channel(NioServerSocketChannel.class)
      .option(ChannelOption.SO_BACKLOG, 100)
      //指定 ChannelHandler,用于处理 channel
      .handler(new LoggingHandler(LogLevel.INFO))
      .childHandler(new ChannelInitializer() {
      @Override
      public void initChannel(SocketChannel ch) throws Exception {
      //ChannelPipeline,基于责任链模式,可以添加多个 ChannelHandler
      ChannelPipeline channelPipeline = ch.pipeline();
      //channelPipeline.addLast(new LoggingHandler(LogLevel.INFO));
      //ChannelHandler,用于处理 channel,实现对接收的数据的处理,实现业务逻辑。
      channelPipeline.addLast(new EchoServerHandler());
      }
      });

      复制代码
           // 开启服务器,将服务器绑定到它要监听连接请求的端口上
           ChannelFuture channelFuture = serverBootstrap.bind(PORT).sync();
      
           // 等待直到服务器socket关闭
           channelFuture.channel().closeFuture().sync();
       } finally {
           //关闭所有 eventLoop,终止线程
           bossGroup.shutdownGracefully();
           workerGroup.shutdownGracefully();
       }

      }
      }

  • EchoServerHandler:

ChannelHandler,用于处理 channel,实现业务逻辑。

复制代码
/**
 * 服务端的 ChannelHandler.
 *
 * ChannelHandler,用于处理 channel,实现对接收的数据的处理,实现业务逻辑。
 * 继承 ChannelInboundHandlerAdapter,用来定义响应入站事件的方法。
 *
 */
@Sharable
@Slf4j
public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * channelRead() :读取 channel 传入的消息
     *
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf buf= (ByteBuf) msg;
        log.info("客户端发来的消息:"+ buf.toString(CharsetUtil.UTF_8) +"\n");
    }

    /**
     * channelReadComplete() :表示当前 ChannelHandler 读取完毕.
     * 执行后会自动跳转到 ChannelPipeline 中的下一个 ChannelHandler.
     *
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        //向客户端返回数据,writeAndFlush() 也可以拆分成 write(msg) 和 flush()
        ctx.writeAndFlush(Unpooled.copiedBuffer("见到你,我也很高兴^_^",CharsetUtil.UTF_8));
    }

    /**
     * exceptionCaught(): 在读取操作期间,有异常抛出时会调用。
     *
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 发生异常时关闭连接
        cause.printStackTrace();
        ctx.close();
    }
}

客户端

在以下示例中,客户端会向服务端发送消息。

  • EchoClient:

    /**

    • 客户端。发送数据给服务端,并接收服务端的响应。

    */
    public final class EchoClient {

    复制代码
      static final String HOST = System.getProperty("host", "127.0.0.1");
      static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
      static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
    
      public static void main(String[] args) throws Exception {
          EventLoopGroup group = new NioEventLoopGroup();
          try {
              Bootstrap bootstrap = new Bootstrap();
              bootstrap.group(group)
               .channel(NioSocketChannel.class)
               .option(ChannelOption.TCP_NODELAY, true)
               .handler(new ChannelInitializer<SocketChannel>() {
                   @Override
                   public void initChannel(SocketChannel socketChannel) throws Exception {
                       ChannelPipeline channelPipeline = socketChannel.pipeline();
                       //channelPipeline.addLast(new LoggingHandler(LogLevel.INFO));
                       //ChannelHandler,用于处理 channel,实现对接收的数据的处理,实现业务逻辑。
                       channelPipeline.addLast(new EchoClientHandler());
                   }
               });
    
              // 开启客户端,连接服务端的端口
              ChannelFuture channelFuture = bootstrap.connect(HOST, PORT).sync();
    
              channelFuture.channel().closeFuture().sync();
          } finally {
              group.shutdownGracefully();
          }
      }

    }

  • EchoClientHandler:

    /**

    • 客户端 的 ChannelHandler.
      */
      @Slf4j
      public class EchoClientHandler extends ChannelInboundHandlerAdapter {

      /**

      • channelActive() 客户端跟服务器的连接建立之后将被调用.

      */
      @Override
      public void channelActive(ChannelHandlerContext ctx) {
      ByteBuf firstMessage = Unpooled.buffer(EchoClient.SIZE);
      byte[] bytes = "见到你很高兴_\n".getBytes(CharsetUtil.UTF_8);
      firstMessage.writeBytes(bytes);
      //向服务器发送数据
      ctx.writeAndFlush(firstMessage);
      }

      @Override
      public void channelRead(ChannelHandlerContext ctx, Object msg) {
      ByteBuf buf = (ByteBuf) msg;
      log.info("服务器发来的消息:" + buf.toString(CharsetUtil.UTF_8));
      }

      @Override
      public void channelReadComplete(ChannelHandlerContext ctx) {
      ctx.flush();
      }

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

执行:

先启动服务端,然后再启动客户端。

服务端收到客户端的信息:

复制代码
11:25:03.081 [nioEventLoopGroup-3-1] INFO com.example.demo.netty.echo.EchoServerHandler - 客户端发来的消息:见到你很高兴^_^

客户端收到服务端的回复:

复制代码
11:25:03.091 [nioEventLoopGroup-2-1] INFO com.example.demo.netty.echo.EchoClientHandler - 服务器发来的消息:见到你,我也很高兴^_^

Netty常用类

以上的这个示例,用到了 Netty常用的类,

详情见:https://blog.csdn.net/sinat_32502451/article/details/133934402

参考资料:

https://zhuanlan.zhihu.com/p/415450910

相关推荐
Larcher2 小时前
React Router 不只是页面跳转:从 SPA 路由到权限守卫的完整实践
javascript·后端
Larcher2 小时前
大模型为什么每次回答都不一样?一文搞懂 Temperature、Top K 与 Top P
javascript·后端
LucianaiB4 小时前
毕业老学长给我留的最后一句话是:“AI 写的,别挂我名。” 我直接 神(Seed Evolving) 来!助我!
后端
IvanCodes4 小时前
RAG 实战教程(一):RAG 工作原理与完整流程——分片、索引、召回、重排和生成
人工智能·后端·agent
·薯条大王5 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
CodeSheep5 小时前
稚晖君公司人事大变动,来了!
前端·后端·程序员
小满zs5 小时前
Go语言第八章(函数)
后端·go
stark张宇7 小时前
实战Go高级特性:Context超时控制、defer资源回收与Channel通信的关键避坑点
后端·go
ZJH__GO8 小时前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
程序员黑豆8 小时前
Windows 系统 Java 环境变量配置全攻略:解决“不是内部或外部命令”
java·前端·ai编程