码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 基于 Netty + RXTX 的无协议 COM 通讯案例实现


    参考

    Netty集成串口RXTX编程,为什么过时了?

    Java版本

    1. java version "1.8.0_231"
    2. Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
    3. Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)

    RXTX版本

    1. # 官网 http://rxtx.qbang.org/wiki/index.php/Download
    2. # 版本 rxtx-2.2pre1-bins

    POM依赖

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.projectlombok</groupId>
    4. <artifactId>lombok</artifactId>
    5. <version>1.18.24</version>
    6. </dependency>
    7. <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
    8. <dependency>
    9. <groupId>io.netty</groupId>
    10. <artifactId>netty-all</artifactId>
    11. <version>4.1.42.Final</version>
    12. </dependency>
    13. </dependencies>

    Com 配置类封装

    1. package com.yushanma.config;
    2. import io.netty.channel.rxtx.RxtxChannelConfig;
    3. import lombok.Data;
    4. /**
    5. * desc
    6. *
    7. * @author Yushanma
    8. * @since 2023/6/4 17:20
    9. */
    10. @Data
    11. public final class ComConfig {
    12. /**
    13. * 串口名称,以COM开头(COM0、COM1、COM2等等)
    14. */
    15. private String serialPortName;
    16. /**
    17. * 波特率, 默认:9600
    18. */
    19. private int baudRate = 9600;
    20. /**
    21. * 数据位 默认8位
    22. * 可以设置的值:SerialPort.DATABITS_5、SerialPort.DATABITS_6、SerialPort.DATABITS_7、SerialPort.DATABITS_8
    23. */
    24. private RxtxChannelConfig.Databits dataBits = RxtxChannelConfig.Databits.DATABITS_8;
    25. /**
    26. * 停止位
    27. * 可以设置的值:SerialPort.STOPBITS_1、SerialPort.STOPBITS_2、SerialPort.STOPBITS_1_5
    28. */
    29. private RxtxChannelConfig.Stopbits stopBits = RxtxChannelConfig.Stopbits.STOPBITS_1;
    30. /**
    31. * 校验位
    32. * 可以设置的值:SerialPort.PARITY_NONE、SerialPort.PARITY_ODD、SerialPort.PARITY_EVEN、SerialPort.PARITY_MARK、SerialPort.PARITY_SPACE
    33. */
    34. private RxtxChannelConfig.Paritybit parity = RxtxChannelConfig.Paritybit.NONE;
    35. }

    字节编解码工具

    1. package com.yushanma.utils;
    2. import java.util.List;
    3. import io.netty.buffer.ByteBuf;
    4. import io.netty.channel.ChannelHandlerContext;
    5. import io.netty.handler.codec.ByteToMessageDecoder;
    6. /**
    7. * 解码器
    8. *
    9. * @author Yushanma
    10. * @since 2023/6/4 17:17
    11. */
    12. public class ByteArrayDecoder extends ByteToMessageDecoder {
    13. @Override
    14. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {
    15. // 标记一下当前的 readIndex 的位置
    16. in.markReaderIndex();
    17. int dataLength = in.readableBytes();
    18. byte[] array = new byte[dataLength];
    19. in.readBytes(array, 0, dataLength);
    20. if(array.length > 0){
    21. out.add(array);
    22. }
    23. }
    24. }
      1. package com.yushanma.utils;
      2. import io.netty.buffer.ByteBuf;
      3. import io.netty.channel.ChannelHandlerContext;
      4. import io.netty.handler.codec.MessageToByteEncoder;
      5. /**
      6. * 编码器
      7. *
      8. * @author Yushanma
      9. * @since 2023/6/4 17:18
      10. */
      11. public class ByteArrayEncoder extends MessageToByteEncoder<byte[]> {
      12. @Override
      13. protected void encode(ChannelHandlerContext ctx, byte[] msg, ByteBuf out) throws Exception {
      14. // 消息体,包含我们要发送的数据
      15. out.writeBytes(msg);
      16. }
      17. }

      Channel 事件处理器

      1. package com.yushanma.handler;
      2. import io.netty.buffer.ByteBuf;
      3. import io.netty.buffer.Unpooled;
      4. import io.netty.channel.ChannelHandler;
      5. import io.netty.channel.ChannelHandlerContext;
      6. import io.netty.channel.SimpleChannelInboundHandler;
      7. import io.netty.util.ReferenceCountUtil;
      8. import java.time.LocalDateTime;
      9. /**
      10. * Channel 事件处理器
      11. * 需要处理什么事件就重写 SimpleChannelInboundHandler 中对应的方法
      12. * @author Yushanma
      13. * @since 2023/6/4 17:19
      14. */
      15. @ChannelHandler.Sharable
      16. public class RxtxHandler extends SimpleChannelInboundHandler<byte[]> {
      17. /**
      18. * 当 COM 口接收到数据时
      19. * 根据不同的进制对数据包进行解码
      20. * 然后执行对应业务逻辑
      21. * @param ctx 上下文
      22. * @param msg 接收到的数据包
      23. * @throws Exception 异常
      24. */
      25. @Override
      26. protected void channelRead0(ChannelHandlerContext ctx, byte[] msg) throws Exception {
      27. // 十六进制发送编解码
      28. int dataLength = msg.length;
      29. ByteBuf buf = Unpooled.buffer(dataLength);
      30. buf.writeBytes(msg);
      31. System.out.println(LocalDateTime.now() + "接收到:");
      32. while(buf.isReadable()){
      33. System.out.print(buf.readByte() + " ");
      34. }
      35. System.out.println();
      36. // 释放资源
      37. ReferenceCountUtil.release(msg);
      38. }
      39. }

      启动类封装

      1. package com.yushanma.server;
      2. import com.yushanma.config.ComConfig;
      3. import com.yushanma.handler.RxtxHandler;
      4. import com.yushanma.utils.ByteArrayDecoder;
      5. import com.yushanma.utils.ByteArrayEncoder;
      6. import io.netty.bootstrap.Bootstrap;
      7. import io.netty.buffer.ByteBuf;
      8. import io.netty.buffer.Unpooled;
      9. import io.netty.channel.ChannelFuture;
      10. import io.netty.channel.ChannelInitializer;
      11. import io.netty.channel.EventLoop;
      12. import io.netty.channel.EventLoopGroup;
      13. import io.netty.channel.oio.OioEventLoopGroup;
      14. import io.netty.channel.rxtx.RxtxChannel;
      15. import io.netty.channel.rxtx.RxtxDeviceAddress;
      16. import io.netty.util.concurrent.GenericFutureListener;
      17. import java.util.concurrent.CompletableFuture;
      18. import java.util.concurrent.Executors;
      19. /**
      20. * desc
      21. *
      22. * @author Yushanma
      23. * @since 2023/6/4 17:23
      24. */
      25. public class RxtxServer {
      26. private RxtxChannel channel;
      27. private ComConfig config;
      28. public RxtxServer(ComConfig config) {
      29. this.config = config;
      30. }
      31. public void createRxtx() throws Exception {
      32. // 串口使用阻塞io
      33. EventLoopGroup group = new OioEventLoopGroup();
      34. try {
      35. Bootstrap bootstrap = new Bootstrap();
      36. bootstrap.group(group)
      37. .channelFactory(() -> {
      38. RxtxChannel rxtxChannel = new RxtxChannel();
      39. rxtxChannel.config()
      40. .setBaudrate(config.getBaudRate()) // 波特率
      41. .setDatabits(config.getDataBits()) // 数据位
      42. .setParitybit(config.getParity()) // 校验位
      43. .setStopbits(config.getStopBits()); // 停止位
      44. return rxtxChannel;
      45. })
      46. .handler(new ChannelInitializer() {
      47. @Override
      48. protected void initChannel(RxtxChannel rxtxChannel) {
      49. rxtxChannel.pipeline().addLast(
      50. // 十六进制形式发送编解码
      51. new ByteArrayDecoder(),
      52. new ByteArrayEncoder(),
      53. new RxtxHandler()
      54. );
      55. }
      56. });
      57. ChannelFuture f = bootstrap.connect(new RxtxDeviceAddress(config.getSerialPortName())).sync();
      58. f.addListener(connectedListener);
      59. f.channel().closeFuture().sync();
      60. } finally {
      61. group.shutdownGracefully();
      62. }
      63. }
      64. // 连接监听
      65. GenericFutureListener connectedListener = (ChannelFuture f) -> {
      66. final EventLoop eventLoop = f.channel().eventLoop();
      67. if (!f.isSuccess()) {
      68. System.out.println("连接失败");
      69. } else {
      70. channel = (RxtxChannel) f.channel();
      71. System.out.println("连接成功");
      72. sendData();
      73. }
      74. };
      75. /**
      76. * 发送数据
      77. */
      78. public void sendData() {
      79. // 十六机制形式发送
      80. ByteBuf buf = Unpooled.buffer(2);
      81. buf.writeByte(3);
      82. buf.writeByte(2);
      83. channel.writeAndFlush(buf.array());
      84. // 文本形式发送
      85. //channel.writeAndFlush("2");
      86. }
      87. public void start() {
      88. CompletableFuture.runAsync(() -> {
      89. try {
      90. // 阻塞的函数
      91. createRxtx();
      92. } catch (Exception e) {
      93. e.printStackTrace();
      94. }
      95. }, Executors.newSingleThreadExecutor());//不传默认使用ForkJoinPool,都是守护线程
      96. }
      97. public static void main(String[] args) {
      98. // 串口连接服务类
      99. ComConfig comConfig = new ComConfig();
      100. comConfig.setSerialPortName("COM1");
      101. comConfig.setBaudRate(9600);
      102. RxtxServer rxtxServer = new RxtxServer(comConfig);
      103. rxtxServer.start();
      104. try {
      105. // 连接串口需要一点时间,这里稍微等待一下
      106. Thread.sleep(5000);
      107. } catch (InterruptedException e) {
      108. e.printStackTrace();
      109. }
      110. // 发送数据
      111. rxtxServer.sendData();
      112. }
      113. }

      测试效果

      这里注意,因为解码是按照十六进制解码,所以需要以“十六进制发送”,“十六进制显示”。

    25. 相关阅读:
      『 基础算法题解 』之双指针(下)
      面过了,起薪30k
      pytest + yaml 框架 -4.用例参数化parameters功能实现
      Redis的 延时双删以及数据一致性
      阿里云无影云电脑角色AliyunServiceRoleForGws什么意思?
      Angular 配置开发环境
      40-SpringBoot
      UI设计师(界面设计)面试题
      Android学习笔记 50. Android 多媒体技术——SoundPool播放音效
      Web前端与其他前端:深度对比与差异性剖析
    26. 原文地址:https://blog.csdn.net/weixin_47560078/article/details/131021932
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号