前言

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

Netty

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

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

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

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

Netty模型selector模式

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

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

半包问题

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

netty模型reactor模式

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

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

SpringBoot使用Netty实现远程调用

maven依赖

<!--lombok-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.2</version><optional>true</optional>
</dependency><!--netty-->
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.17.Final</version>
</dependency>

服务端部分

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<SocketChannel> {@Overrideprotected 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 {/*** 客户端连接会触发*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.info("Channel active......");}/*** 客户端发消息会触发*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {log.info("服务器收到消息: {}", msg.toString());ctx.write("你也好哦");ctx.flush();}/*** 发生异常触发*/@Overridepublic 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 {@Overrideprotected 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<SocketChannel>() {@Overrideprotected 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;@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.info("客户端Active .....");}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {log.info("客户端收到消息: {}", msg.toString());this.responseResult = ResponseResult.success(msg.toString(), CouponTypeEnum.OPERATE_SUCCESS.getCouponTypeDesc());ctx.close();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

验证

测试接口

@RestController
@Slf4j
public class UserController {@PostMapping("/helloNetty")@MethodLogPrintpublic ResponseResult helloNetty(@RequestParam String msg) {return NettyClientUtil.helloNetty(msg);}
}

访问测试接口

服务端打印信息

客户端打印信息

作者:溪源的奇思妙想
原文链接:https://blog.csdn.net/weixin_40990818/article/details/109248198

netty 多个 本地udp端口_如何在SpringBoot中,使用Netty实现远程调用?相关推荐

  1. netty的使用场景,线程模型以及如何在springboot中使用netty?

    文章目录 1. 为什么使用netty? 2. netty的线程模型 3. 在springboot中使用netty 4. netty的核心API解释 5. netty中的ByteBuf 1. 为什么使用 ...

  2. linux 查看开放的端口_如何在 Linux 中查看正在使用的端口

    在对网络连接或特定于应用程序的问题进行故障排除时,首先要检查的是应该在系统上实际使用哪些端口以及哪个应用程序正在侦听特定端口.本文会介绍如何使用 netstat , ss 和 lsof 命令找出哪些服 ...

  3. hosts文件 端口_在Linux系统中使用Vim读写远程文件

    大家好,我是良许. 今天我们讨论一个 Vim 使用技巧--用 Vim 读写远程文件.要实现这个目的,我们需要使用到一个叫 netrw.vim 的插件.从 Vim 7.x 开始,netrw.vim 就被 ...

  4. iptables 打开端口_如何在iptables中打开端口?

    iptables 打开端口 How to open a port, say 3389, in iptables to allow incoming traffics to it? 如何在iptable ...

  5. linux 更改ssh端口_如何在Linux中更改SSH端口-简易指南

    linux 更改ssh端口 The default port on SSH is 22. But for security reasons, it's a good idea to change SS ...

  6. 一键搭建php本地测试环境_如何在PHP中设置本地调试环境

    一键搭建php本地测试环境 Recently I started focusing more on PHP, and I needed to set up a local debugging envi ...

  7. c++定义一个动态对象数组_如何在Python中自定义一个可被调用的对象实例?

    前言 在关于Python描述符函数的详解三篇中,我们有提到如何基于类创建一个"描述符函数",之所以能够基于类创建这样一个概念,是因为用到了类中的__call__属性,从前述文章中可 ...

  8. .jar中没有主清单属性_如何在springboot中使用PageHelper分页插件

    目录: PageHelper简介 使用maven引入相关的jar 配置PageHelper方言 编写业务逻辑代码 PageInfo类中几个常用属性的注释 一. PageHelper简介 PageHel ...

  9. jwt token 过期刷新_如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

最新文章

  1. 【手写系列】纯手写实现一个高可用的RPC
  2. CEPH给用户创建读写权限
  3. oracle错误处理及实操-【INS-20802】
  4. 02年六代雅阁的整备质量_2020年宝安第八批更新计划:联投地产5.4万㎡“工改”项目...
  5. Java案例:利用JDBC访问SQL Server数据库
  6. 中职计算机优质课课件ppt,中职优质课 交集课件.ppt
  7. hive if函数_数据仓库,Hive中使用 != 或 lt;gt;; 符号进行条件过滤时的坑
  8. Elsevier(爱思唯尔)论文模板下载地址及说明
  9. matlab误差分析报告,误差分析实验报告
  10. 电脑的热点手机连接不上怎么办
  11. 证明:二阶导函数大于零时为凹函数
  12. java 计算百分比_java前后台计算百分比(保留2位小数)
  13. C++程序设计:税费计算
  14. 计算机发展初期 承载信息的媒体,多媒体习题与答案(1).doc
  15. 微信小程序地理位置API使用流程
  16. 一节课精通Emmet编写开发工具-姜威-专题视频课程
  17. 4-逻辑控制器:Logic Controller
  18. 基于java家庭理财记账系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  19. 用CSS3咋写“跳动的心”?
  20. CSDN如何公开私密博客

热门文章

  1. OKR与影响地图,别再傻傻分不清
  2. Hudi自带工具DeltaStreamer的实时入湖最佳实践
  3. 我的编辑器能玩贪吃蛇,一起玩不?
  4. 案例集锦|科技赋能,华为云GaussDB助千行百业数字化转型
  5. 【万字长文】探讨可信构架之道
  6. 【华为云技术分享】数据湖数据库,别再傻傻分不清了
  7. azure不支持哪些语句 sql_排查 Azure SQL 数据库的常见连接问题 - Azure SQL Database | Microsoft Docs...
  8. 韩顺平php视频笔记44 php小练习表单提交
  9. SpykeTorch: Efficient Simulation of Convolutional Spiking Neural Networks With at Most One Spike per
  10. CSNN: An Augmented Spiking based Framework with Perceptron-Inception