2. Netty使用JSerialComm进行串口读取(二)

2. Netty使用JSerialComm进行串口读取(二)

前面提到了有两个问题:

第一个问题:串口读取超时异常一路传播到最后也没有处理。

第二个问题:即使处理了该异常,程序仍然退出,这不能满足一些实际使用要求需求。该问题与设置很长的读取超时时间没关系,无论多长到时间后总会退出。

现在开始这些问题的处理。

2.1.问题1:串口读取超时异常一路传播到最后也没有处理

​ 先解决较容易处理的问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JWzgPW34-1680531562179)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image002.jpg)]

​ 测试程序中使用如下语句设置读取超时时间:

config.setReadTimeout(10000);

​ 即使设置读取超时时间长一点,如10秒,但如果十秒后没数据,也会出现超时异常,并提示

警告: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.

com.fazecast.jSerialComm**.SerialPortTimeoutException**: The read operation timed out before any data was returned.

​ 这个提示得意思是:异常一路传播到最后也没有处理,这通常意味着管道中的最后一个处理程序没有处理异常。

问题解决方法:

​ 定义一个异常处理类ExceptionCaughtHandler,放在pipeline的最后用来处理各类异常。

package io.netty.example.jserialcomm;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.jsc.JSerialCommReadTimeoutException;
import com.fazecast.jSerialComm.SerialPortTimeoutException;
/**
 * 定义一个异常处理类,放在pipeline的最后,处理各类异常
 */
public class ExceptionCaughtHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //System.out.println("Test Exception");
        if (cause instanceof SerialPortTimeoutException) {
            System.out.println("串口读取超时");
            //超时后,定义业务需要的处理,例如可重新读取数据
        }
        else {
            super.exceptionCaught(ctx, cause);
         }
    }
}

​ 把异常处理器添加到pipeline最后面。

pipeline.addLast(new ExceptionCaughtHandler());

测试运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XJfAydHe-1680531562181)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image004.jpg)]

成功监测到该异常。

2.2. 问题2:即使处理了该异常,程序仍然退出

问题现象

​ 从测试结果看,即使处理了该异常,程序仍然退出,这不能满足一些实际使用要求需求。

例如希望有数据时能正常读取数据,没有数据时给出读取超时提示并继续等待数据到来,这样就可以把串口的状态提示给用户或记录到日志系统。

​ 同时该问题与设置很长的读取超时时间没关系,无论多长到时间后总会退出。

问题分析

​ 直接查看Netty源代码并调试代码,发现JSerialCommChannel类是继承得 OioByteStreamChannel类。程序运行到OioByteStreamChannel类doReadBytes函数的buf.writeBytes语句行时,如果串口没有数据可读取,将抛出com.fazecast.jSerialComm.SerialPortTimeoutException异常导致程序退出。

@Override
protected int doReadBytes(ByteBuf buf) throws Exception {
    final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
    allocHandle.attemptedBytesRead(Math.max(1, Math.min(available(), buf.maxWritableBytes())));
    return buf.writeBytes(is, allocHandle.attemptedBytesRead());
}

解决方法

​ 在JSerialCommChannel类中重载doReadBytes函数,并处理异常,抛出自定义异常JSerialCommReadTimeoutException在串口应用测试程序中处理该异常。

​ 在重载代码中很方便查看抛出的具体是什么异常?(SerialPortTimeoutException)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHUi4Yn2-1680531562182)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image006.jpg)]

com.fazecast.jSerialComm.SerialPortTimeoutException: The read operation timed out before any data was returned.

在netty-transport-jserialcomm自定义异常JSerialCommReadTimeoutException类。

package io.netty.channel.jsc;

public class JSerialCommReadTimeoutException extends RuntimeException{
    public JSerialCommReadTimeoutException(){

    }
    public JSerialCommReadTimeoutException(String msg){
        super(msg);
    }
}

在JSerialCommChannel类重载函数doReadBytes中抛出自定义异常JSerialCommReadTimeoutException。

try {
    return buf.writeBytes(is, i);
}
catch (IOException io)
{
    //串口在给定时间内没数据读取
    //抛出自定义串口读取超时异常处理异常JSerialCommReadTimeoutException
    throw new JSerialCommReadTimeoutException("The Serial read operation timed out before any data was returned");
}

​ 然后在串口应用测试序中修改ExceptionCaughtHandler类的exceptionCaught函数。将SerialPortTimeoutException异常修改为为JSerialCommReadTimeoutException异常。

 
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    //System.out.println("Test Exception");
    //if (cause instanceof SerialPortTimeoutException) {
    if (cause instanceof JSerialCommReadTimeoutException) {

        System.out.println("串口读取超时");
        //超时后,克定义业务需要的处理,例如可重新读取数据
    }
    else {
        super.exceptionCaught(ctx, cause);
     }
}

运行测试程序进行测试,测试结果如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zMdl7354-1680531562182)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image008.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3m5rtBz3-1680531562183)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image010.jpg)]
修改后的程序可以提示读取超时信息,同时也不退出程序,还可以正常接收串口数据,达到预期效果。

最终修改好的库与测试代码下载地址为:《Netty使用JSerialComm进行串口读取的更新库源代码及问题修正

介绍如下:
Netty-Transport-jSerialComm升级版本(v2.0.0)
更新如下:
1)依赖的Netty从 4.1.13.Final版本升级到 4.1.82.Final版本
2)依赖的jSerialComm 从1.3.11版本升级到2.9.2版本
3)处理两个问题:
第一个问题是:串口读取超时异常一路传播到最后也没有处理。
第二个问题是:即使处理了该异常,测试程序仍然退出,这不能满足一些实际使用要求需求。该问题与设置很长的读取超时时间没关系,无论多长到时间后总会退出。
4)打包生成 netty-transport-jserialcomm-2.0.0.jar、netty-transport-jserialcomm-2.0.0-javadoc.jar、netty-transport-jserialcomm-2.0.0-sources.jar三个包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静水深流(探索者)

优化算法慢慢学习

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值