刚刚读取刚打开的SerialPort时,只读取一个字节

Sin*_*atr 2 c# serial-port

奇怪的问题.

当我从com-port读取时SerialPort.Read(),如果数据到达,则在第一次调用时只读取一个字节,忽略count参数和超时内可用的字节数.所有进一步的读数都没问题,只有第一个问题

使用SerialPort.DiscardInBuffer()或关闭/打开(重新打开)com-port将再次导致第一次读取的问题.

这是一些代码:

var port = new SerialPort();
port.PortName = "com2";
port.BaudRate = 9600;
port.WriteTimeout = 1000;
port.ReadTimeout = 1000;
port.Open();

// ... send some data first

var read = new byte[10];
if (port.Read(read, 0, read.Length) != read.Length)
{
    // always here at first reading no matter what
}

// ... send some data again

if (port.Read(read, 0, read.Length) != read.Length)
{
    // not here anymore (unless error)
}
Run Code Online (Sandbox Code Playgroud)

如果在Read()调用时已经可以读取指定数量的数据,则不会出现问题.


一些解释.

Read()是同步阅读.它将在收到指定数量的数据或超时超时时返回.看起来,TimeoutException只有在收到零字节时才会抛出.如果在读取请求的数据量之前超时已到期,则函数将返回读取的字节数.因此,必须将返回值与请求进行比较,以查看读数是否正常.

但第一次通话有一个问题:

如果在超时期间到达0字节,则第一次正确调用等待超时并触发TimeoutException.如果至少有1个字节到达,则函数立即结束,忽略超时和请求的完全读取的字节数.

这就是我的看法.我错了吗?我该怎么办?


一些更多的测试.插入Thread.Sleep()以确保在Read()调用时,将有所有可用数据,将使问题消失.

从逻辑上讲,让我们只为第一次通话添加睡眠.好极了.什么????问题现在出现在第二次通话第二次通话时.换句话说,问题出现在第一个Read()中,没有所有数据可用但只有一次.

Nik*_*vic 7

因为在读取时,其他字节没有到达,它将只读取一个字节,因为队列中只有一个字节.因此,如果存在至少一个字节,它将不会等待所需的字节数,因为超时已发生,但它不会抛出异常.如果没有,它将抛出超时异常.因此,您应该尝试阅读,直到您根据需要读取多个字节(在您的情况下为10).你可以尝试这样的事情:

int count = 0;
var read = new byte[10];
while ((count += port.Read(read, count, read.Length - count)) != read.Length) ;
Run Code Online (Sandbox Code Playgroud)

但是,如果发生超时,也许这可以加强代码:

int count = 0;
var read = new byte[10];
while (count < read.Length)
{
    try
    {
        count += port.Read(read, count, read.Length - count);
    }
    catch (TimeoutException te)
    {
        //maybe increase ReadTimeout or something, use exponential backoff, your call
    }
}
Run Code Online (Sandbox Code Playgroud)