构建异步高并发服务器:Netty与Spring Boot的完美结合

前言

在这里插入图片描述
「作者主页」:雪碧有白泡泡
「个人网站」:雪碧的个人网站
请添加图片描述

ChatGPT体验地址

请添加图片描述

文章目录

  • 前言
  • IO
  • Netty
      • 1. 引入依赖
      • 2. 服务端
      • 4. 客户端
      • 结果
  • 总结
      • 引导类-Bootstarp和ServerBootstrap
      • 连接-NioSocketChannel
      • 事件组-EventLoopGroup和NioEventLoopGroup
  • 送书活动

IO

在Java基础中,IO流是一个重要操作,先上八股

在这里插入图片描述

  1. BIO:传统的IO,同步阻塞,一个连接一个线程。一般不怎么使用
  2. AIO:JDK7引入的,异步非阻塞IO
  3. NIO:JDK1.4之后新的API,是多路复用,允许你一次性处理多个连接,而不需要等待每个连接的完成。(NIO 多路复用的核心概念是 Selector(选择器)和 Channel(通道)通过Channel、Buffer和Selector来进行数据传输和事件处理)

Netty

Netty是建立在NIO之上的一个框架,提供了更高级的抽象,如ChannelHandler和EventLoop,简化了事件处理和网络编程。
执行流程如下图
在这里插入图片描述

具有高性能,高可靠性,高可扩展性,还支持多种协议

我们以聊天流程为例

  1. 服务端启动
  2. 客户端启动
  3. 客户端启动连接上的时候,告知服务端
  4. 服务端读取到客户端的信息后立即发送信息给客户端
  5. 客户端收到信息后也发送给服务端

1. 引入依赖

  		<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.76.Final</version></dependency>

2. 服务端

@Slf4j
public class NettyServer {private final static int PORT = 9012;public static void main(String[] args) throws InterruptedException {/*** 包含childGroup,childHandler,config,继承的父类AbstractBootstrap包括了parentGroup* */ServerBootstrap bootstrap = new ServerBootstrap();/*** EventLoopGroup用于处理所有ServerChannel和Channel的所有事件和IO* */EventLoopGroup parentGroup = new NioEventLoopGroup();EventLoopGroup childGroup = new NioEventLoopGroup();try {/*** 绑定两个事件组* */bootstrap.group(parentGroup, childGroup)/*** 初始化socket,定义tcp连接的实例* 内部调用ReflectiveChannelFactory实现对NioServerSocketChannel实例化* channelFactory是在AbstractBootstrap,也就是bootstrap的父类* */.channel(NioServerSocketChannel.class)/*** 添加处理器* ChannelInitializer包括了Set<ChannelHandlerContext> initMap** 这里比较有趣的事情就是使用被注册的channel去初始化其他的channel,* 等初始化结束后移除该channel* 所以SocketChannel是一个工具,** 在bind绑定端口的时候,进行初始化和注册initAndRegister,* 通过channel = channelFactory.newChannel()得到初始化channel* init(channel)真正开始初始化,* p = channel.pipeline()得到ChannelPipeline,* p.addLast开始添加* ch.eventLoop().execute将childHandler赋值并开启一个任务setAutoRead* 所以最后在监听读取的时候将会按照下面添加的channel进行读取** ChannelInitializer继承了ChannelInboundHandlerAdapter* 间接继承ChannelHandlerAdapter,ChannelInboundHandler,* */.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();/*** ByteBuf和String之间的转换**  Decoders解密*  pipeline.addLast("frameDecoder", new {@link LineBasedFrameDecoder}(80))*  pipeline.addLast("stringDecoder", new {@link StringDecoder}(CharsetUtil.UTF_8))**  Encoder加密*  pipeline.addLast("stringEncoder", new {@link StringEncoder}(CharsetUtil.UTF_8))**  使用上面的加密解密后就可以直接读取字符串*   void channelRead({@link ChannelHandlerContext} ctx, String msg) {*       ch.write("Did you say '" + msg + "'?\n")*  }** */pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());//自定义处理器pipeline.addLast(new ServerHandler1());}});ChannelFuture future = bootstrap.bind(PORT).sync();log.info("服务器已启动");future.channel().closeFuture().sync();} finally {parentGroup.shutdownGracefully();childGroup.shutdownGracefully();}}
}

这段代码实现了一个使用Netty框架的服务器端,它监听指定的端口并处理客户端的连接请求。

  1. 创建一个ServerBootstrap实例,用于启动服务器。
  2. 创建两个EventLoopGroup实例,parentGroup用于处理服务器的连接请求,childGroup用于处理客户端的数据通信。
  3. 绑定事件组到ServerBootstrap实例。
  4. 指定使用的NioServerSocketChannel作为服务器套接字通道的实现类。
  5. 添加处理器到ChannelInitializer中,该处理器负责初始化和配置新连接的SocketChannel
  6. 在处理器中,通过ChannelPipeline添加了如下处理器:
    • StringDecoder:处理传入的字节数据,并将其解码为字符串。
    • StringEncoder:处理传出的字符串数据,并将其编码为字节。
    • ServerHandler1:自定义的处理器,用于处理客户端发送的消息。
  7. 绑定服务器的端口号,启动服务器。
  8. 等待服务器的关闭事件。
  1. 处理器
@Slf4j
public class ServerHandler1 extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {log.info("Client Address ====== {},读取的信息:{}", ctx.channel().remoteAddress(),msg);ctx.channel().writeAndFlush("服务端writeAndFlush:我是服务端");ctx.fireChannelActive();//睡眠TimeUnit.MILLISECONDS.sleep(500);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {//打印异常cause.printStackTrace();//关闭Channel连接,并通知ChannelFuture,通常是出现异常或者是完成了操作ctx.close();}
}

4. 客户端

@Slf4j
public class NettyClient {private final static int PORT = 9012;private final static String IP = "localhost";public static void main(String[] args) throws InterruptedException {/*** 服务端是ServerBootstrap,客户端是Bootstrap* Bootstrap引导channel连接,UDP连接用bind方法,TCP连接用connect方法* */Bootstrap bootstrap = new Bootstrap();/*** 服务端是EventLoopGroup,客户端是NioEventLoopGroup* 这里创建默认0个线程,一个线程工厂,一个选择器提供者* */NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();try {bootstrap.group(eventLoopGroup)/*** 初始化socket,定义tcp连接的实例* */.channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();/*** 进行字符串的转换* */pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));/*** 自定义处理器* */pipeline.addLast(new ClientHandler1());}});ChannelFuture future = bootstrap.connect(IP, PORT).sync();log.info("客户端访问");future.channel().closeFuture().sync();} finally {eventLoopGroup.shutdownGracefully();}}
}

这段代码实现了一个使用Netty框架的客户端,它连接到指定的服务器端并与服务器进行通信。

  1. 创建一个Bootstrap实例,用于启动客户端。
  2. 创建一个NioEventLoopGroup实例,用于处理客户端的事件和IO操作。
  3. 绑定事件组到Bootstrap实例。
  4. 指定使用的NioSocketChannel作为客户端套接字通道的实现类。
  5. 添加处理器到ChannelInitializer中,该处理器负责初始化和配置客户端连接的SocketChannel
  6. 在处理器中,通过ChannelPipeline添加了如下处理器:
    • StringDecoder:处理传入的字节数据,并将其解码为字符串。
    • StringEncoder:处理传出的字符串数据,并将其编码为字节。
    • ClientHandler1:自定义的处理器,用于处理与服务器之间的通信。
  7. 使用Bootstrapconnect()方法连接到指定的服务器IP和端口。
  8. 等待连接完成。
  9. 在连接成功后,打印日志信息。
  10. 等待客户端的关闭事件。
  1. 处理器
@Slf4j
public class ClientHandler1 extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {log.info("客户端读取的信息:{}", msg);ctx.channel().writeAndFlush("客户端writeAndFlush:我是客户端");TimeUnit.MILLISECONDS.sleep(5000);}/*** 当事件到达pipeline时候触发*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ctx.channel().writeAndFlush("客户端:开始聊天");}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();//关闭Channel连接ctx.close();}}

在这里插入图片描述

结果

服务端日志

Client Address ====== /127.0.0.1:63740,读取的信息:客户端:开始聊天
Client Address ====== /127.0.0.1:63740,读取的信息:客户端writeAndFlush:我是客户端
Client Address ====== /127.0.0.1:63740,读取的信息:客户端writeAndFlush:我是客户端

客户端日志

客户端读取的信息:服务端writeAndFlush:我是服务端
客户端读取的信息:服务端writeAndFlush:我是服务端

总结

在这里插入图片描述

引导类-Bootstarp和ServerBootstrap

Bootstarp和ServerBootstrap被称为引导类,使你的应用程序和网络层相隔离。类似java项目的启动类。

连接-NioSocketChannel

客户端和服务端的启动都是采用配置的channel去连接处理器,这里服务端和客户端是用NioSocketChannel

事件组-EventLoopGroup和NioEventLoopGroup

客户端使用的是NioEventLoopGroup,服务端使用的是EventLoopGroup。 服务端和客户端的引导类启动后实现了配置的运行,客户端和服务端的连接都是采用NioSocketChannel。 连接的流程:

  1. 客户端创建一个channel
  2. channel对应一个EventLoop,EventLoop存放到NioEventLoopGroup中
  3. 服务端监听到后,创建一个channel连接,channel对应一个EventLoop,EventLoop存放到子的EventLoopGroup,父的事件组负责监听,一个事件对应一个子事件组。
    在这里可以认为父是boss监听组,子是工作组。
  4. 当客户端发送信息的时候,先被父监听,然后将异步调用工作组。
  5. 消息会经过事件组的所有处理器。

实际上服务端的事件组也可以使用NioEventLoopGroup。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5e676670b49e40dd83155e76094e9017.png

送书活动

在这里插入图片描述

  • 🎁本次送书1~3本【取决于阅读量,阅读量越多,送的越多】👈
  • ⌛️活动时间:截止到2024-1月10号
  • ✳️参与方式:关注博主+三连(点赞、收藏、评论)
    购买链接:https://item.jd.com/13836258.html

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/329336.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字人克隆系统开发公司?

广州硅基技术开发限公司是一家位于中国广东省广州市的科技公司。该公司专注于人工智能&#xff08;AI&#xff09;领域的研发和创新。广州硅基以技术创新和解决方案为核心&#xff0c;致力于为客户提供高质量的人工智能产品和服务。 广州硅基技术的主要业务包括但不限于&#x…

面试算法90:环形房屋偷盗

题目 一条环形街道上有若干房屋。输入一个数组表示该条街道上的房屋内财产的数量。如果这条街道上相邻的两幢房屋被盗就会自动触发报警系统。请计算小偷在这条街道上最多能偷取的财产的数量。例如&#xff0c;街道上5家的财产用数组[2&#xff0c;3&#xff0c;4&#xff0c;5…

二叉树的深度和高度问题(算法村第八关白银挑战)

二叉树的最大深度 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null…

基于SSM的基金投资交易管理网站的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

深入理解神经网络训练与反向传播

目录 前言1 损失函数1.1 交叉熵&#xff08;Cross Entropy&#xff09;&#xff1a;1.2 均方差&#xff08;Mean Squared Error&#xff09;&#xff1a; 2 梯度下降与学习率2.1 梯度下降2.2 学习率 3 正向传播与反向传播3.1 正向传播3.2 反向传播 4 链式法则和计算图4.1 链式法…

数据结构入门到入土——链表(2)

目录 一&#xff0c;与链表相关的题目&#xff08;2&#xff09; 1.输入两个链表&#xff0c;找出它们的第一个公共节点 2.给定一个链表&#xff0c;判断链表中是否有环 3.给定一个链表&#xff0c;返回链表开始入环的第一个节点&#xff0c;若无则返回null 一&#xff0c;…

autodl学术加速

今天使用autodl加载预训练BERT模型失败&#xff0c;在官方文档里面找到了官方给的代理使用方法。 直接在bash输入&#xff1a; 开启学术加速&#xff1a; source /etc/network_turbo取消学术加速&#xff1a; unset http_proxy && unset https_proxy据说是只能访问这…

RabbitMQ高级

文章目录 一.消息可靠性1.生产者消息确认2.消息持久化3.消费者确认4.消费者失败重试 MQ的一些常见问题 1.消息可靠性问题:如何确保发送的消息至少被消费一次 2.延迟消息问题:如何实现消息的延迟投递 3.高可用问题:如何避免单点的MQ故障而导致的不可用问题 4.消息堆积问题:如…

MySQL——用户管理

目录 一.用户管理 二.用户 1.用户信息 2.创建用户 3.删除用户 4. 修改用户密码 三.数据库的权限 1.给用户授权 2.回收权限 一.用户管理 如果我们只能使用root用户&#xff0c;root的权限非常大,这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理&#xff…

Packet Tracer - Configure AAA Authentication on Cisco Routers

Packet Tracer - 在思科路由器上配置 AAA 认证 地址表 目标 在R1上配置本地用户账户&#xff0c;并使用本地AAA进行控制台和vty线路的身份验证。从R1控制台和PC-A客户端验证本地AAA身份验证功能。配置基于服务器的AAA身份验证&#xff0c;采用TACACS协议。从PC-B客户端验证基…

阿里云服务器在哪个城市?云服务器地域节点分布表

2024年阿里云服务器地域分布表&#xff0c;地域指数据中心所在的地理区域&#xff0c;通常按照数据中心所在的城市划分&#xff0c;例如华北2&#xff08;北京&#xff09;地域表示数据中心所在的城市是北京。阿里云地域分为四部分即中国、亚太其他国家、欧洲与美洲和中东&…

Tracert 与 Ping 程序设计与实现(2024)

1.题目描述 了解 Tracert 程序的实现原理&#xff0c;并调试通过。然后参考 Tracert 程序和计算机网络教材 4.4.2 节&#xff0c; 计算机网络 课程设计指导书 2 编写一个 Ping 程序&#xff0c;并能测试本局域网的所有机器是否在线&#xff0c;运行界面如下图所示的 QuickPing …