SerialPort.BaseStream.ReadAsync отсутствует первый байт

Я пытаюсь использовать класс SerialPort в.net.

Я решил сохранить свой сервис асинхронным, поэтому я использую асинхронные методы на SerialPort.BaseStream,

В моем асинхронном методе я записываю byte[] в последовательный порт, затем начинаю чтение, пока я не получил больше данных в течение n миллисекунд, и возвращаю этот результат.

Проблема, однако, в том, что я, кажется, пропускаю первый байт во всех ответах, кроме самого первого ответа после открытия последовательного порта.

Если я закрываю порт после каждого ответа (Чтение) и снова открываю его перед выполнением нового запроса (Запись), первый байт не пропускается. Это, однако, часто приводит к "Access to the port 'COM4' is denied." исключение, если я пытаюсь открыть порт слишком рано после закрытия. Также кажется очень ненужным открывать / закрывать для каждой записи / чтения.

Вот как выглядит мой метод:

private async Task<byte[]> SendRequestAsync(byte[] request)
{    
    // Write the request
    await _serialPort.BaseStream.WriteAsync(request, 0, request.Length);

    var buffer = new byte[BUFFER_SIZE];
    bool receiveComplete = false;
    var bytesRead = 0;

    // Read from the serial port
    do
    {
        var responseTask = _serialPort.BaseStream.ReadAsync(buffer, bytesRead, BUFFER_SIZE - bytesRead);
        if (await Task.WhenAny(responseTask, Task.Delay(300)) == responseTask)
        {
            bytesRead += responseTask.Result;
        }
        else
            receiveComplete = true;


    } while (!receiveComplete);

    var response = new byte[bytesRead];
    Array.Copy(buffer, 0, response, 0, bytesRead);

    return response;
}

Что-то явно не так в том, как я это делаю? Есть ли более умный способ добиться того же асинхронно?

1 ответ

Просто потому, что вы не наблюдаете последний ReadAsync() не означает, что он отменен, он все еще работает, что, очевидно, означает, что он читает первый байт следующего сообщения.

Что вы должны сделать, это отменить последний ReadAsync() используя CancellationToken, Обратите внимание, что возможна гонка между тайм-аутом и чтением, но я предполагаю, что, если тайм-аут истек, чтение не может быть завершено без другой записи.

Код будет выглядеть так:

var cts = new CancellationTokenSource();

do
{
    var responseTask = _serialPort.BaseStream.ReadAsync(
        buffer, bytesRead, BUFFER_SIZE - bytesRead, cts.Token);

    if (await Task.WhenAny(responseTask, Task.Delay(300)) == responseTask)
    {
        bytesRead += responseTask.Result;
    }
    else
    {
        cts.Cancel();
        receiveComplete = true;
    }
} while (!receiveComplete);

Обратите внимание, что и причина, и решение - мои догадки, вполне возможно, что я ошибаюсь в отношении одного или обоих из них.

Другие вопросы по тегам