超时分串口读超时和串口写超时,主要是读超时,即ReadTimeout与Read方法之间的超时。下面谈谈他们之间的意义和实现。
Read方法是阻塞的,它一直在读串口接收缓冲区中的数据,如果接收缓冲区有数据,Read方法则返回一个或多个字节数据;如果Read方法在等待ReadTimeout毫秒时间内,串口接收区一直没有任何数据,则Read方法将甩ExceptionTimeout异常。注意,Read(outBuf, offset, count)阻塞读取的不是非等到count个字节数据,而是当前接收缓冲区大于等于1小于等于count个字节数据,即只要有数据Read方法就立刻返回。
由于Read方法的阻塞性,所以我们必须防止(如串口物理断开) Read永远不返回,而导致程序卡死。方法有:
1. 设置ReadTimeout属性为合理值,其默认值为-1,即Read永不可能因为ReadTimeout而超时返回。
2. 先判断serialPort.BytesToRead大于0,再调用Read方法,则Read肯定会返回。
代码段一:
int nStartTime = Environment.TickCount;
while(true)
{
int nNowTime = Environment.TickCount;
if(nNowTime – nStartTime > 360) //等待360ms
{
Console.WriteLine(“等待360ms后超时”);
break;
}
if(serialPort.BytesToRead > 35) //用户业务数据包长度
{
int nLen = serialPort.Read(outBuf, 0, 35);
DealData(outBuf, nLen); //验证合法包,然后处理业务
break;
}
//时间消耗在循环过程中,可在这加一行 Thread.Sleep(20);
}
代码段二:
serialPort.ReadTimeout = 1000; //等待1000ms 初始化
//接收处理函数
try
{
int nLen = serialPort.Read(outBuf, 0, serialPort. BytesToRead); //如果接收区一直没数据,时间消耗在这,等1000ms后甩TimeoutException异常
if(nLen > 0)
{
DealData(outBuf, nLen); //进全局数据队列,然后分析队列里的合法数据包
}
}
catch (TimeoutException ex)
{
Console.WriteLine("通信超时");
}