栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Netty】telnet helloworld

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Netty】telnet helloworld

From:https://liudongdong1.github.io/


Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。是一个NIO客户端服务器框架,可以快速轻松地开发协议服务器和客户端等网络应用程序。它极大地简化并简化了TCP和UDP套接字服务器等网络编程。Netty经过精心设计,具有丰富的协议,如FTP,SMTP,HTTP以及各种二进制和基于文本的传统协议。

绿色的部分Core核心模块,包括零拷贝、API库、可扩展的事件模型。

橙色部分Protocol Support协议支持,包括Http协议、webSocket、SSL(安全套接字协议)、谷歌Protobuf协议、zlib/gzip压缩与解压缩、Large File Transfer大文件传输等等。

红色的部分Transport Services传输服务,包括Socket、Datagram、Http Tunnel等等。

1. 代码编写

代码模块主要分为服务端和客户端。 主要实现的业务逻辑: 服务端启动成功之后,客户端也启动成功,这时服务端会发送一条信息给客户端。客户端或者telnet发送一条信息到服务端,服务端会根据逻辑回复客户端一条客户端,当客户端或者telent发送bye给服务端,服务端和客户端断开链接。

 netty-helloworld
    ├── client
      ├── Client.class -- 客户端启动类
      ├── ClientHandler.class -- 客户端逻辑处理类
      ├── ClientInitializer.class -- 客户端初始化类
    ├── server 
      ├── Server.class -- 服务端启动类
      ├── ServerHandler -- 服务端逻辑处理类
      ├── ServerInitializer -- 服务端初始化类
.1. 服务器端代码 .1. Server 入口
public final class Server {
      public  static void main(String[] args) throws Exception {
          //Configure the server
          //创建两个EventLoopGroup对象
          //创建boss线程组 用于服务端接受客户端的连接
          EventLoopGroup bossGroup = new NioEventLoopGroup(1);
          // 创建 worker 线程组 用于进行 SocketChannel 的数据读写
          EventLoopGroup workerGroup = new NioEventLoopGroup();
          try {
              // 创建 ServerBootstrap 对象
              ServerBootstrap b = new ServerBootstrap();
              //设置使用的EventLoopGroup
              b.group(bossGroup,workerGroup)
                  //设置要被实例化的为 NioServerSocketChannel 类
                      .channel(NioServerSocketChannel.class)
                  // 设置 NioServerSocketChannel 的处理器
                      .handler(new LoggingHandler(LogLevel.INFO))
                   // 设置连入服务端的 Client 的 SocketChannel 的处理器
                      .childHandler(new ServerInitializer());
              // 绑定端口,并同步等待成功,即启动服务端
              ChannelFuture f = b.bind(8888);
              // 监听服务端关闭,并阻塞等待
              f.channel().closeFuture().sync();
          } finally {
              // 优雅关闭两个 EventLoopGroup 对象
              bossGroup.shutdownGracefully();
              workerGroup.shutdownGracefully();
          }
      }
}
.2. ServerInitializer

使用Netty编写业务层的代码,我们需要继承ChannelInboundHandlerAdapter 或SimpleChannelInboundHandler类

  • 继承SimpleChannelInboundHandler类之后,会在接收到数据后会自动release掉数据占用的Bytebuffer资源。并且继承该类需要指定数据格式。
  • 继承ChannelInboundHandlerAdapter则不会自动释放,需要手动调用**ReferenceCountUtil.release()**等方法进行释放。继承该类不需要指定数据格式。 (可以防止数据未处理完就被释放了)
public class ServerInitializer extends ChannelInitializer {
      private static final StringDecoder DECODER = new StringDecoder();
      private static final StringEncoder ENCODER = new StringEncoder();
  
      private static final ServerHandler SERVER_HANDLER = new ServerHandler();
  
  
      @Override
      public void initChannel(SocketChannel ch) throws Exception {
          ChannelPipeline pipeline = ch.pipeline();
  
          // 添加帧限定符来防止粘包现象
          pipeline.addLast(new DelimiterbasedframeDecoder(8192, Delimiters.lineDelimiter()));
          // 解码和编码,应和客户端一致
          pipeline.addLast(DECODER);
          pipeline.addLast(ENCODER);
 
          // 业务逻辑实现类
          pipeline.addLast(SERVER_HANDLER);
      }
  }
.3. ServerHandler
@Sharable
  public class ServerHandler extends SimpleChannelInboundHandler {
      
      @Override
      public void channelActive(ChannelHandlerContext ctx) throws Exception {
          // 为新连接发送庆祝
          ctx.write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!rn");
          ctx.write("It is " + new Date() + " now.rn");
          ctx.flush();
      }
  
      //业务逻辑处理
      @Override
      public void channelRead0(ChannelHandlerContext ctx, String request) throws Exception {
          // Generate and write a response.
          String response;
          boolean close = false;
          if (request.isEmpty()) {
              response = "Please type something.rn";
          } else if ("bye".equals(request.toLowerCase())) {
              response = "Have a good day!rn";
              close = true;
          } else {
              response = "Did you say '" + request + "'?rn";
          }
  
          ChannelFuture future = ctx.write(response);
  
          if (close) {
              future.addListener(ChannelFutureListener.CLOSE);
          }
      }
  
      @Override
      public void channelReadComplete(ChannelHandlerContext ctx) {
          ctx.flush();
      }
 
      //异常处理
      @Override
      public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
          cause.printStackTrace();
          ctx.close();
      }
  }
.2. 客户端代码

客户端过滤其这块基本和服务端一致。不过需要注意的是,传输协议、编码和解码应该一致。

.1. ClientInitializer
public class ClientInitializer extends ChannelInitializer {
      private static final StringDecoder DECODER = new StringDecoder();
      private static final StringEncoder ENCODER = new StringEncoder();
  
      private static final ClientHandler CLIENT_HANDLER = new ClientHandler();
  
  
      @Override
      public void initChannel(SocketChannel ch) {
          ChannelPipeline pipeline = ch.pipeline();
          pipeline.addLast(new DelimiterbasedframeDecoder(8192, Delimiters.lineDelimiter()));
          pipeline.addLast(DECODER);
          pipeline.addLast(ENCODER);
  
          pipeline.addLast(CLIENT_HANDLER);
      }
  }
.2. ClientHandler 业务处理逻辑
@Sharable
  public class ClientHandler extends SimpleChannelInboundHandler {
      //打印读取到的数据
      @Override
      protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
          System.err.println(msg);
      }
      //异常数据捕获
      @Override
      public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
          cause.printStackTrace();
          ctx.close();
      }
  }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/332659.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号