Springboot-cli 开发脚手架系列

Netty系列:Springboot+Netty优雅的开发websocket高性能服务器


文章目录

  • Springboot-cli 开发脚手架系列
  • 前言
    • 1. 环境
    • 2. 引入websocket编码解码器
    • 3. 编写websocket处理器
    • 4. 效果演示
    • 5. 源码分享

前言

首先我们需要使用Netty搭建基础的tcp框架,参考Springboot使用Netty优雅的创建高性能TCP服务器,接下来我们开始集成websocket。

1. 环境

  • pom.xml
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>${netty-all.version}</version></dependency>
  • yml开启日记debug级别打印
# 日记配置
logging:level:# 开启debug日记打印com.netty: debug

2. 引入websocket编码解码器

这里我们需要加入websocket编码解码器,因为websocket的握手是通过http完成的,所以我们还需要加入http的编码器。

/*** Netty 通道初始化** @author qiding*/
@Component
@RequiredArgsConstructor
public class ChannelInit extends ChannelInitializer<SocketChannel> {private final MessageHandler messageHandler;@Overrideprotected void initChannel(SocketChannel channel) {channel.pipeline()// 心跳时间.addLast("idle", new IdleStateHandler(0, 0, 60, TimeUnit.SECONDS))// 对http协议的支持..addLast(new HttpServerCodec())// 对大数据流的支持.addLast(new ChunkedWriteHandler())// 聚合 Http 将多个requestLine、requestHeader、messageBody信息转化成单一的request或者response对象.addLast(new HttpObjectAggregator(8192))// 聚合 websocket 的数据帧,因为客户端可能分段向服务器端发送数据.addLast(new WebSocketFrameAggregator(1024 * 62))// 添加消息处理器.addLast("messageHandler", messageHandler);}}

3. 编写websocket处理器

  • WebsocketMessageHandler 处理器主要负责处理握手协议和文本交互
/*** Websocket 消息处理器** @author qiding*/
@Slf4j
@Component
public class WebsocketMessageHandler {/*** 对webSocket 首次握手进行解析*/public void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {// 首次握手进行校验this.isFullHttpRequest(ctx, request);// 获取请求uriString uri = request.uri();// 参数分别是 (ws地址,子协议,是否扩展,最大frame长度)WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory(getWebSocketLocation(request), null, true, 5 * 1024 * 1024);WebSocketServerHandshaker handShaker = factory.newHandshaker(request);if (handShaker == null) {WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());} else {handShaker.handshake(ctx.channel(), request);}WebSocketSession.setChannelShaker(ctx.channel().id(), handShaker);}/*** 处理消息*/public void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {// 获取webSocket 会话WebSocketServerHandshaker handShaker = WebSocketSession.getChannelShaker(ctx.channel().id());// 关闭if (frame instanceof CloseWebSocketFrame) {log.debug("收到关闭请求");handShaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());return;}// 握手PING/PONGif (frame instanceof PingWebSocketFrame) {ctx.writeAndFlush(new PongWebSocketFrame(frame.content().retain()));return;}// 文本接收和回复if (frame instanceof TextWebSocketFrame) {log.debug("收到消息:\n{}", ((TextWebSocketFrame) frame).text());ctx.writeAndFlush(new TextWebSocketFrame("服务器接收成功!"));return;}// 二进制文本if (frame instanceof BinaryWebSocketFrame) {ctx.writeAndFlush(frame.retain());}}/*** 判断是否是正确的websocket 握手协议*/private void isFullHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {if (!request.decoderResult().isSuccess()) {log.error("非webSocket请求");this.sendResponse(ctx, request, new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.BAD_REQUEST, ctx.alloc().buffer()));ctx.close();return;}if (!HttpMethod.GET.equals(request.method())) {log.error("非GET请求");this.sendResponse(ctx, request, new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.FORBIDDEN, ctx.alloc().buffer()));ctx.close();}}/*** SSL支持采用wss:*/private String getWebSocketLocation(FullHttpRequest request) {return "ws://" + request.headers().get(HttpHeaderNames.HOST) + "/websocket";}/*** http 握手通用响应*/private void sendResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse resp) {HttpResponseStatus status = resp.status();if (status != HttpResponseStatus.OK) {ByteBufUtil.writeUtf8(resp.content(), status.toString());HttpUtil.setContentLength(req, resp.content().readableBytes());}boolean keepAlive = HttpUtil.isKeepAlive(req) && status == HttpResponseStatus.OK;HttpUtil.setKeepAlive(req, keepAlive);ChannelFuture future = ctx.write(resp);if (!keepAlive) {future.addListener(ChannelFutureListener.CLOSE);}}
}
  • 修改主消息处理器MessageHandler.java ,加入握手过程处理
/*** 消息处理,单例启动** @author qiding*/
@Slf4j
@Component
@ChannelHandler.Sharable
@RequiredArgsConstructor
public class MessageHandler extends SimpleChannelInboundHandler<WebSocketFrame> {private final WebsocketMessageHandler websocketHandler;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {if (msg instanceof FullHttpRequest) {websocketHandler.handleHttpRequest(ctx, (FullHttpRequest) msg);log.debug("\n");log.debug("客户端{}握手成功!", ctx.channel().id());}super.channelRead(ctx, msg);}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {log.debug("\n");log.debug("channelId:" + ctx.channel().id());websocketHandler.handleWebSocketFrame(ctx, frame);}@Overridepublic void channelInactive(ChannelHandlerContext ctx) {log.debug("\n");log.debug("断开连接");// 释放缓存ChannelStore.closeAndClean(ctx);WebSocketSession.clear(ctx.channel().id());}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("\n");log.debug("成功建立连接,channelId:{}", ctx.channel().id());super.channelActive(ctx);}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {log.debug("心跳事件时触发");}
}

4. 效果演示

服务类和启动类基础模块的搭建参考开头提供的连接进行搭建即可,这里就不重复了
这里启动项目,以postman测试为例

  • postman模拟客户端连接服务器

  • 服务器

5. 源码分享

  • Springboot-cli开发脚手架,集合各种常用框架使用案例,完善的文档,致力于让开发者快速搭建基础环境并让应用跑起来。
  • 项目源码github地址
  • 项目源码国内gitee地址

Netty实战:Springboot+Netty+websocket优雅的高性能服务器 (附源码下载)相关推荐

  1. SpringBoot图书管理系统设计与实现(附源码下载地址)

    文章目录 01 系统概述 02 开发工具及技术选型 03 运行环境 04 用户分析 05 功能分析 06 数据库设计 07 项目工程结构及说明 08 部分功能展示及源码 8.1 首页 8.2 图书管理 ...

  2. Springboot实战:Springboot+Netty优雅的创建websocket客户端 (附源码下载)

    Springboot-cli 开发脚手架系列 Netty系列:Springboot+Netty优雅的创建websocket客户端 (附源码下载) 文章目录 Springboot-cli 开发脚手架系列 ...

  3. 05【Verilog实战】AMBA 3 APB接口设计(附源码RTL/TB)

    官方手册:点击下载 脚  本:makefile 工  具:vcs & verdi 写在前面 这个专栏的内容记录的是个人学习过程,博文中贴出来的代码是调试前的代码,方便bug重现. 调试后的程序 ...

  4. 03【Verilog实战】UART通信协议,半双工通信方式(附源码)

    脚 本:makefile(点击直达) 应用工具:vcs 和 verdi 写在前面 这个专栏的内容记录的是个人学习过程,博文中贴出来的代码是调试前的代码,方便bug重现. 调试后的程序提供下载,[下载地 ...

  5. Netty实战:Springboot+Netty+protobuf开发高性能服务器 (附源码下载)

    Springboot-cli 开发脚手架系列 Netty系列:Springboot使用Netty集成protobuf开发高性能服务器 文章目录 Springboot-cli 开发脚手架系列 简介 1. ...

  6. Spring Cloud微服务实战:手把手带你整合eurekazuulfeignhystrix(附源码)

    Spring Cloud微服务实战:手把手带你整合eureka&zuul&feign&hystrix(附源码) Spring Cloud简介 Spring Cloud是一个基于 ...

  7. Springboot+vue开发的图书借阅管理系统项目源码下载-P0029

    前言 图书借阅管理系统项目是基于SpringBoot+Vue技术开发而来,功能相对比较简单,分为两个角色即管理员和学生用户,核心业务功能就是图书的发布.借阅与归还,相比于一些复杂的系统,该项目具备简单 ...

  8. SpringBoot 和 Vue 前后端分离教程(附源码)

    编辑:业余草 来源:https://www.xttblog.com/?p=4851 昨天,一位网友问我要 SpringBoot + Vue 的源码项目.其实网上有很多,我这里分享一个项目的简单教程,授 ...

  9. 基于 Vue 和 SpringBoot 实现的博客系统(附源码)

    今天给大家分享一个基于 Vue 和 SpringBoot 实现的博客系统! 源码在文章结尾处,大家自行下载即可,我设置的免积分下载! 一.主要功能 1.前端 后台管理系统采用Vue开发. 文章模块,支 ...

最新文章

  1. Swift - 简单的原生与网页交互
  2. 新Hibernate SessionFactory().getCurrentSession()猫腻
  3. c# redis 如何设置过期时间_Redis 过期时间与内存管理
  4. 论文 参考文献的格式说明
  5. tensorflow 保存训练loss_tensorflow2.0保存和加载模型 (tensorflow2.0官方教程翻译)
  6. 超60亿元,新华三领衔华为锐捷中兴中标中国移动高端路由器和交换机集采
  7. 学计算机修图,宅家修图很简单 手机电脑都可以修出大片的感觉
  8. Flink DataStream 关联维表实战
  9. H.264熵编码分析
  10. DIY制作修改替换PPC手机短信背景图片的技巧
  11. 虚拟机上安装openwrt并开发ipk包
  12. OrCAD Capture原理图中批量修改网络名
  13. 用python进行精细中文分句(基于正则表达式)
  14. Python批量获取手机号码归属地(图文展示)
  15. 一文简单理解反向代理和正向代理模型
  16. 技术学习:Python(21)|爬虫篇|selenium自动化操作浏览器
  17. Java实现替换Word中文本
  18. Google Earth网页版初探
  19. Chat Bot(聊天机器人)自动化测试脚本来解决人工测试的问题
  20. SIP协议-04 SIP头域

热门文章

  1. linux开机更改root密码怎么办,Linux(RedHat) 开机时修改root密码
  2. java 定义integer64位_Java-int和Integer的区别
  3. RFID技术在制造和仓储中的应用价值
  4. 超级马里奥Run的精妙设计
  5. 你的技术成长战略是什么?
  6. AI 智能写情诗、藏头诗模型训练
  7. Android Gradle源码分析
  8. 养宠受追捧,国内宠物食品电商为何始终萎靡不振?
  9. VCard(.VCF) 2.1(rfc-2426)标准通信薄基本格式
  10. 精灵标注助手的安装及使用