热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringBoot使用Netty实现远程调用的示例

这篇文章主要介绍了SpringBoot使用Netty实现远程调用的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着

前言

众所周知我们在进行网络连接的时候,建立套接字连接是一个非常消耗性能的事情,特别是在分布式的情况下,用线程池去保持多个客户端连接,是一种非常消耗线程的行为。那么我们该通过什么技术去解决上述的问题呢,那么就不得不提一个网络连接的利器――Netty.

正文 Netty

Netty是一个NIO客户端服务器框架:

  • 它可快速轻松地开发网络应用程序,例如协议服务器和客户端。
  • 它极大地简化和简化了网络编程,例如TCPUDP套接字服务器。

NIO是一种非阻塞IO ,它具有以下的特点

  • 单线程可以连接多个客户端。
  • 选择器可以实现但线程管理多个Channel,新建的通道都要向选择器注册。
  • 一个SelectionKey键表示了一个特定的通道对象和一个特定的选择器对象之间的注册关系。
  • selector进行select()操作可能会产生阻塞,但是可以设置阻塞时间,并且可以用wakeup()唤醒selector,所以NIO是非阻塞IO

Netty模型selector模式

它相对普通NIO的在性能上有了提升,采用了:

  • NIO采用多线程的方式可以同时使用多个selector
  • 通过绑定多个端口的方式,使得一个selector可以同时注册多个ServerSocketServer
  • 单个线程下只能有一个selector,用来实现Channel的匹配及复用

在这里插入图片描述

半包问题

TCP/IP在发送消息的时候,可能会拆包,这就导致接收端无法知道什么时候收到的数据是一个完整的数据。在传统的BIO中在读取不到数据时会发生阻塞,但是NIO不会。为了解决NIO的半包问题,NettySelector模型的基础上,提出了reactor模式,从而解决客户端请求在服务端不完整的问题。

netty模型reactor模式

selector的基础上解决了半包问题。

在这里插入图片描述

上图,简单地可以描述为"boss接活,让work干":manReactor用来接收请求(会与客户端进行握手验证),而subReactor用来处理请求(不与客户端直接连接)。

SpringBoot使用Netty实现远程调用

maven依赖



 org.projectlombok
 lombok
 1.18.2
 true




 io.netty
 netty-all
 4.1.17.Final

服务端部分

NettyServer.java:服务启动监听器

@Slf4j
public class NettyServer {
  public void start() {
    InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8082);
    //new 一个主线程组
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    //new 一个工作线程组
    EventLoopGroup workGroup = new NioEventLoopGroup(200);
    ServerBootstrap bootstrap = new ServerBootstrap()
        .group(bossGroup, workGroup)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ServerChannelInitializer())
        .localAddress(socketAddress)
        //设置队列大小
        .option(ChannelOption.SO_BACKLOG, 1024)
        // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
        .childOption(ChannelOption.SO_KEEPALIVE, true);
    //绑定端口,开始接收进来的连接
    try {
      ChannelFuture future = bootstrap.bind(socketAddress).sync();
      log.info("服务器启动开始监听端口: {}", socketAddress.getPort());
      future.channel().closeFuture().sync();
    } catch (InterruptedException e) {
      log.error("服务器开启失败", e);
    } finally {
      //关闭主线程组
      bossGroup.shutdownGracefully();
      //关闭工作线程组
      workGroup.shutdownGracefully();
    }
  }
}

ServerChannelInitializer.java:netty服务初始化器

/**
* netty服务初始化器
**/
public class ServerChannelInitializer extends ChannelInitializer {
  @Override
  protected void initChannel(SocketChannel socketChannel) throws Exception {
    //添加编解码
    socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
    socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
    socketChannel.pipeline().addLast(new NettyServerHandler());
  }
}

NettyServerHandler.java:netty服务端处理器

/**
* netty服务端处理器
**/
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
  /**
   * 客户端连接会触发
   */
  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
    log.info("Channel active......");
  }

  /**
   * 客户端发消息会触发
   */
  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    log.info("服务器收到消息: {}", msg.toString());
    ctx.write("你也好哦");
    ctx.flush();
  }


  /**
   * 发生异常触发
   */
  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    cause.printStackTrace();
    ctx.close();
  }
}

RpcServerApp.java:SpringBoot启动类

/**
* 启动类
*
*/
@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class RpcServerApp extends SpringBootServletInitializer {
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(RpcServerApp.class);
  }

  /**
   * 项目的启动方法
   *
   * @param args
   */
  public static void main(String[] args) {
    SpringApplication.run(RpcServerApp.class, args);
    //开启Netty服务
    NettyServer nettyServer =new NettyServer ();
    nettyServer.start();
    log.info("======服务已经启动========");
  }
}

客户端部分

NettyClientUtil.java:NettyClient工具类

/**
* Netty客户端
**/
@Slf4j
public class NettyClientUtil {

  public static ResponseResult helloNetty(String msg) {
    NettyClientHandler nettyClientHandler = new NettyClientHandler();
    EventLoopGroup group = new NioEventLoopGroup();
    Bootstrap bootstrap = new Bootstrap()
        .group(group)
        //该参数的作用就是禁止使用Nagle算法,使用于小数据即时传输
        .option(ChannelOption.TCP_NODELAY, true)
        .channel(NioSocketChannel.class)
        .handler(new ChannelInitializer() {
          @Override
          protected void initChannel(SocketChannel socketChannel) throws Exception {
            socketChannel.pipeline().addLast("decoder", new StringDecoder());
            socketChannel.pipeline().addLast("encoder", new StringEncoder());
            socketChannel.pipeline().addLast(nettyClientHandler);
          }
        });
    try {
      ChannelFuture future = bootstrap.connect("127.0.0.1", 8082).sync();
      log.info("客户端发送成功....");
      //发送消息
      future.channel().writeAndFlush(msg);
      // 等待连接被关闭
      future.channel().closeFuture().sync();
      return nettyClientHandler.getResponseResult();
    } catch (Exception e) {
      log.error("客户端Netty失败", e);
      throw new BusinessException(CouponTypeEnum.OPERATE_ERROR);
    } finally {
      //以一种优雅的方式进行线程退出
      group.shutdownGracefully();
    }
  }
}

NettyClientHandler.java:客户端处理器

/**
* 客户端处理器
**/
@Slf4j
@Setter
@Getter
public class NettyClientHandler extends ChannelInboundHandlerAdapter {

  private ResponseResult responseResult;

  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
    log.info("客户端Active .....");
  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    log.info("客户端收到消息: {}", msg.toString());
    this.respOnseResult= ResponseResult.success(msg.toString(), CouponTypeEnum.OPERATE_SUCCESS.getCouponTypeDesc());
    ctx.close();
  }

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

验证

测试接口

@RestController
@Slf4j
public class UserController {

  @PostMapping("/helloNetty")
  @MethodLogPrint
  public ResponseResult helloNetty(@RequestParam String msg) {
    return NettyClientUtil.helloNetty(msg);
  }
}

访问测试接口

在这里插入图片描述

服务端打印信息

在这里插入图片描述

客户端打印信息

在这里插入图片描述

源码

项目源码可从的我的github中获取:github源码地址

到此这篇关于SpringBoot使用Netty实现远程调用的示例的文章就介绍到这了,更多相关SpringBoot Netty远程调用内容请搜索编程笔记以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程笔记!

原文链接:https://blog.csdn.net/weixin_40990818/article/details/109248198


推荐阅读
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 本文介绍如何使用JavaScript中的for循环来创建一个九九乘法表,适合初学者学习循环结构的应用。 ... [详细]
  • Asynchronous JavaScript and XML (AJAX) 的流行很大程度上得益于 Google 在其产品如 Google Suggest 和 Google Maps 中的应用。本文将深入探讨 AJAX 在 .NET 环境下的工作原理及其实现方法。 ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • 本文详细介绍了如何在Oracle VM VirtualBox中实现主机与虚拟机之间的数据交换,包括安装Guest Additions增强功能,以及如何利用这些功能进行文件传输、屏幕调整等操作。 ... [详细]
  • OBS Studio自动化实践:利用脚本批量生成录制场景
    本文探讨了如何利用OBS Studio进行高效录屏,并通过脚本实现场景的自动生成。适合对自动化办公感兴趣的读者。 ... [详细]
  • 本文介绍了如何利用X_CORBA实现远程对象调用,并通过多个示例程序展示了其功能与应用,包括基础的Hello World示例、文件传输工具以及一个完整的聊天系统。 ... [详细]
  • 深入探讨:Actor模型如何解决并发与分布式计算难题
    在现代软件开发中,高并发和分布式系统的设计面临着诸多挑战。本文基于Akka最新文档,详细探讨了Actor模型如何有效地解决这些挑战,并提供了对并发和分布式计算的新视角。 ... [详细]
  • Spring Security基础配置详解
    本文详细介绍了Spring Security的基础配置方法,包括如何搭建Maven多模块工程以及具体的安全配置步骤,帮助开发者更好地理解和应用这一强大的安全框架。 ... [详细]
  • 一家位于长沙的知名网络安全企业,现面向全国诚聘高级后端开发工程师,特别欢迎具有一线城市经验的技术精英回归故乡,共创辉煌。 ... [详细]
  • 本文探讨了如何利用RxJS库在AngularJS应用中实现对用户单击和拖动操作的精确区分,特别是在调整区域大小的场景下。 ... [详细]
  • Fiddler 安装与配置指南
    本文详细介绍了Fiddler的安装步骤及配置方法,旨在帮助用户顺利抓取用户Token。文章还涵盖了一些常见问题的解决方案,以确保安装过程顺利。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
author-avatar
魏承辉符合_821
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有