5月份有个项目,需要通过程序给串口发送信号,通过串口通讯到供应商控制板,从而控制硬件设备的开启和关闭。其实这是一个很简单的东西,之前也写过,就是个java串口通讯开发,根据之前经验,使用rxtxSerial的包来开发,直接用输出流也好,用modbus也好,都可以用。
rxtxSerial这玩意好像是sun做的,后面被抛弃了,一直没人维护和更新。我用的版本是2.2,用起来也比较麻烦,还要先把rxtxxParallel.dll和rxtxSerial.dll放到系统目录下(windows的话就是system32)的,还要把jar包放jdk目录下。
开发也比较顺利,很快实现了控制逻辑,但是很快就发现一个严重的问题,程序直接闪退。我用的tomcat来部署,tomcat服务直接给我宕掉了,没有报错,没有异常获取,直接就宕机了,打印戛然而止,没有任何信息。后来通过tomcat生成的dmp文件和增加打印行数,定位到代码:
这个setRate就是我自己写的一个方法:
- public static void setRate(String modbusSpeed) {
- try {
- mSerialport = openPort("COM8", CAMERA_BAUD_RATE);
- logger.info("打开COM8串口完成");
- byte[] speedSignStr = speedToRate(modbusSpeed);
- sendToPort(mSerialport, speedSignStr);
- logger.info("发送行频信号完成");
- Thread.sleep(500);// 行频信号与启动信号间隔0.5秒
- String startSign = "73 17 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 65";
- byte[] start = hexStrToBinaryStr(startSign);
- sendToPort(mSerialport, start);
- logger.info("发送开始信号完成");
- closePort(mSerialport);
- logger.info("关闭COM8串口完成");
- } catch (PortInUseException e) {
- System.out.println("串口已被占用!");
- } catch (Exception e) {
- e.printStackTrace();
- }
是为了给相机设置行频的,大概的逻辑就是openPort打开串口,sendToPort把字节数组发送给串口,然后再发一组数据过去,最后closePort关闭串口。这边出了问题。
tomcat在闪退之后,会自动在bin目录下生成对应的错误文件,供查看错误使用,内容包括报错类型、报错时间、报错代码、报错时各类资源使用情况等。具体都代表什么,有专门相关文章介绍怎么读懂tomcat dmp文件的,查一下就好了。
上图说的很明白了,错误类型C,就是rxtxSerial.dll报的错,引起的进程崩溃。
9804这一行,点名报错的是一个open。也就是说,打开串口的时候有问题。open方法:
- // 通过端口名识别端口
- CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
- // 打开端口,并给端口名字和一个timeout(打开操作的超时时间)
- CommPort commPort = portIdentifier.open(portName, 2000);
具体实现,是rxtx底层的了,我java这边看不到。
5月份就出了这个问题,问题是定位到了,但是不知道为什么会发生这个问题,发生的时间、频率也没有规律,可能有时候连续一星期都正常,有的时候一天要闪退好几次。
我曾经思考,是不是我连续对同一个串口发送两次数据,对同一串口操作过于频繁导致的底层出错?后来我在两次发送中间加了个sleep(500),让两次发送之间停半秒。没想到这个问题就此消失,后来真就没闪退过。一直持续到了8月中旬。
最近这个问题又重新出现了,我就知道不是所谓串口操作过于频繁地问题了,因为这个发生频率是在是毫无道理可言,同一套代码可以稳定跑3个多月没问题,出问题的时候平均一天两次,代码和外部环境都没有变,实在是毫无道理可言。
我想了又想,只可能是rxtxSerial这破玩意自己底层有问题,至于什么问题,对于我来说是黑盒的,我只能归咎于它,是底层代码本来就有问题,还是说跟jdk版本不适配,不去管。
我上网搜索了以下,果然有不少人都遇到了rxtxSerial造成java进程闪退的问题,我按照网上的说话更换了依赖包,使用一个叫purejavacomm的包,直接在pom文件里加了maven依赖:
- <dependency>
- <groupId>com.github.purejavacomm</groupId>
- <artifactId>purejavacomm</artifactId>
- <version>1.0.1.RELEASE</version>
- </dependency>
保存以下,就自动从maven库给你下载下来了,很方便地是,这个purejavacomm里面的各方法和类跟rxtxSerial是一模一样的,也就是说你换了依赖包,但是代码几乎可以一字不变,你只需要在引用(java里是import)那边直接换就可以了,具体的业务代码一个字母都不要改。
再也不用像rxtx那样,移植的时候还要带着dll文件了,purejavacomm直接在项目了,很方便。目前使用purejavacomm后,已经一周没有出现闪退,后续再继续观察