Springboot-cli 开发脚手架系列

Netty系列:Springboot+Netty优雅的创建websocket客户端 (附源码下载)


文章目录

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

前言

首先我们需要使用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()// 每隔60s的时间触发一次userEventTriggered的方法,并且指定IdleState的状态位是WRITER_IDLE,事件触发给服务器发送ping消息.addLast("idle", new IdleStateHandler(0, 60, 0, TimeUnit.SECONDS))// 添加解码器.addLast(new HttpClientCodec()).addLast(new ChunkedWriteHandler()).addLast(new HttpObjectAggregator(1024 * 1024 * 10)).addLast(new WebSocketFrameAggregator(1024 * 62))// 添加消息处理器.addLast("messageHandler", messageHandler);}
}

3. 编写websocket处理器

  • 修改消息处理器MessageHandler.java
  • 增加两个全局变量,保存当前连接
    /*** websocket会话存储*/private WebSocketClientHandshaker handShaker;/*** 用于回调判断握手是否成功*/private ChannelPromise handshakeFuture;
  • 连接成功开始握手
 @Overridepublic void handlerAdded(ChannelHandlerContext ctx) {// 保存Promisethis.handshakeFuture = ctx.newPromise();}
@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("\n");log.debug("握手开始,channelId:{}", ctx.channel().id());handShaker = WebSocketClientHandshakerFactory.newHandshaker(new URI("ws://" + WebsocketClient.connectedIp + ":" + WebsocketClient.connectedPort + "/ws"), WebSocketVersion.V13, null, false, new DefaultHttpHeaders());handShaker.handshake(ctx.channel());super.channelActive(ctx);}
  • 完整代码
/*** 消息处理,单例启动** @author ding*/
@Slf4j
@Component
@ChannelHandler.Sharable
@RequiredArgsConstructor
public class MessageHandler extends SimpleChannelInboundHandler<Object> {private WebSocketClientHandshaker handShaker;private ChannelPromise handshakeFuture;@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {// 连接前执行this.handshakeFuture = ctx.newPromise();}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Object message) {log.debug("\n");log.debug("channelId:" + ctx.channel().id());// 判断是否正确握手if (!this.handShaker.isHandshakeComplete()) {try {this.handShaker.finishHandshake(ctx.channel(), (FullHttpResponse) message);log.debug("websocket Handshake 完成!");this.handshakeFuture.setSuccess();} catch (WebSocketHandshakeException e) {log.debug("websocket连接失败!");this.handshakeFuture.setFailure(e);}return;}// 握手失败响应if (message instanceof FullHttpResponse) {FullHttpResponse response = (FullHttpResponse) message;log.error("握手失败!code:{},msg:{}", response.status(), response.content().toString(CharsetUtil.UTF_8));}WebSocketFrame frame = (WebSocketFrame) message;// 消息处理if (frame instanceof TextWebSocketFrame) {TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;log.debug("收到消息: " + textFrame.text());}if (frame instanceof PongWebSocketFrame) {log.debug("pong消息");}if (frame instanceof CloseWebSocketFrame) {log.debug("服务器主动关闭连接");ctx.close();}}@Overridepublic void channelInactive(ChannelHandlerContext ctx) {log.debug("\n");log.debug("连接断开");}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("\n");log.debug("握手开始,channelId:{}", ctx.channel().id());handShaker = WebSocketClientHandshakerFactory.newHandshaker(new URI("ws://" + WebsocketClient.connectedIp + ":" + WebsocketClient.connectedPort + "/ws"), WebSocketVersion.V13, null, false, new DefaultHttpHeaders());handShaker.handshake(ctx.channel());super.channelActive(ctx);}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {log.debug("超时事件时触发");if (evt instanceof IdleStateEvent) {IdleStateEvent event = (IdleStateEvent) evt;// 当我们长时间没有给服务器发消息时,发送ping消息,告诉服务器我们还活跃if (event.state().equals(IdleState.WRITER_IDLE)) {log.debug("发送心跳");ctx.writeAndFlush(new PingWebSocketFrame());}} else {super.userEventTriggered(ctx, evt);}}
}

4. http测试接口编写

  • pom.xml加入web依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • HttpApi .java
/*** 模拟发送api** @author qiding*/
@RequiredArgsConstructor
@RestController
@Slf4j
public class HttpApi {private final WebsocketClient websocketClient;/*** 消息发布*/@GetMapping("/send")public String send(String message) {websocketClient.getSocketChannel().writeAndFlush(new TextWebSocketFrame(message));return "发送成功";}/*** 消息发布*/@PostMapping("/send/json")public String send(@RequestBody JSONObject body) {websocketClient.getSocketChannel().writeAndFlush(new TextWebSocketFrame(body.toJSONString()));return "发送成功";}/*** 连接*/@GetMapping("connect")public String connect(String ip, Integer port) throws Exception {websocketClient.connect(ip, port);return "重启指令发送成功";}/*** 重连*/@GetMapping("reconnect")public String reconnect() throws Exception {websocketClient.reconnect();return "重启指令发送成功";}
}

5. 效果演示

  • 客户端服务类和启动类基础模块的搭建参考开头提供的连接进行搭建即可,这里就不重复了

  • 我们这里通过Springboot+Netty优雅的开发websocket高性能服务器搭建的服务器配合测试

  • 测试接口

基础接口 http://localhost:9999

# 1. 发送消息
/send?message=hello
# 2. 连接
/connect?ip=192.168.0.99&port=20000
# 3. 重连
/reconnect
# 5. 发送json
```json
Request URL:  http://localhost:9999/send/json
Request Method: POST
Request Headers:
{"Content-Type":"application/json"
}
Request Body:
{"msgId": 1,"type": 1,"data": {"message":"hello"}
}
  • 效果

6. 源码分享

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

Springboot实战:Springboot+Netty优雅的创建websocket客户端 (附源码下载)相关推荐

  1. Netty实战:Springboot+Netty+websocket优雅的高性能服务器 (附源码下载)

    Springboot-cli 开发脚手架系列 Netty系列:Springboot+Netty优雅的开发websocket高性能服务器 文章目录 Springboot-cli 开发脚手架系列 前言 1 ...

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

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

  3. SpringCloud-服务注册与实现-Eureka创建服务提供者(附源码下载)

    场景 SpringCloud-服务注册与实现-Eureka创建服务注册中心(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

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

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

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

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

  6. SpringCloud-服务注册与实现-Eureka创建服务注册中心(附源码下载)

    场景 SpringCloud学习之运行第一个Eureka程序: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/90611451 S ...

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

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

  8. springboot项目文档源码_基于SpringBoot和Vue的企业级中后台项目(附源码)

    简介 SpringBoot和Vue,前后端分离,我们开源一套漂亮的代码和一套整洁的代码规范,让大家在这浮躁的代码世界里感受到一股把代码写好的清流!同时又让开发者节省大量的时间,减少加班,快乐工作,热爱 ...

  9. SpringBoot整合Elasticsearch详细步骤以及代码示例(附源码)

    准备工作# 环境准备# JAVA版本 Copy java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1. ...

最新文章

  1. 开始使用asp.net ajax的控件工具包AJAX Control Toolkit
  2. idea自动为行尾加分号
  3. SpringSecurity remember功能基本实现
  4. 分布式架构中一致性解决方案——Zookeeper集群搭建
  5. iis7.0 https访问显示403访问被拒绝_提高网站访问性能——Tomcat优化
  6. js改变select下拉框默认选择的option
  7. 通过反射实现圆角ImageView
  8. box2d 计算下一帧的位置/角度
  9. 扇贝有道180907每日一句
  10. SQL Server 2014 软件安装教程
  11. mac 思科 链路聚合_Cisco交换机 链路聚合
  12. 毕设外文文献查找方法
  13. Redis文档链接(含官方中文)
  14. 家中买的计算机配置,配置,教您买电脑主要看哪些配置
  15. 【Laravel笔记】13. 模型的关联写入
  16. KNN实战莺尾花数据集
  17. 基于ip-iq变换的谐波检测算法,并联型APF 有源电力滤波器 谐波电流检测
  18. Deep Hashing Network for Efficient Similarity Retrieval
  19. 黑客大会:defcon_来自深层网络的故事:地下黑客的雇用
  20. post和get方式在http请求中的区别

热门文章

  1. Printers(一) 打印机配置信息
  2. 基于QGraphicsView实现绘画曲线注意点
  3. ltv价值 应用_浅谈LTV模型的概念、算法及作用意义
  4. 计算机的企业管理中的应用,计算机技术在企业管理中的具体应用
  5. pingunknown host www.xxx.com解决方案
  6. Django丨ORM - 单表实例
  7. vue2兼容IE浏览器遇见的问题
  8. ThinkPHP学习笔记(三)有关项目中URL的路径问题和使用frame搭建页面的
  9. 微信小程序布局display flex布局介绍
  10. 电脑上计算机上的英语是什么意思,[电脑的英文是什么意思啊]电脑的英文是什么意思...