Неверное количество считываемых данных из System.Net.Sockets.Read

Пишу код на C# занимающийся опросом железок по протоколу Modbus TCP-IP. Сейчас код выглядит так, но были испробованы все версии чтения данных, и синхронные и асинхронные, и пробовал использовать TcpClient, результат всегда один.

// Connect asynchronous client
asyncConnection = new Socket(IPAddress.Parse(ip).AddressFamily, SocketType.Stream, ProtocolType.Tcp);                
asyncConnection.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
asyncConnection.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, _timeout);
asyncConnection.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, _timeout);
asyncConnection.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);

// Write asynchronous data
asyncConnection.BeginSend(write_data, 0, write_data.Length, SocketFlags.None, new AsyncCallback(OnSend), null);

// Write asynchronous data acknowledge
private void OnSend(System.IAsyncResult result)
{
    int size = asyncConnection.EndSend(result);                
    if (result.IsCompleted == false) CallException(excSendFailt);
    asyncConnection.BeginReceive(asyncConnectionBuffer, 0, asyncConnectionBuffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), asyncConnection);                
}

// Write asynchronous data response
private void OnReceive(System.IAsyncResult result)
{
    asyncConnection.EndReceive(result);
    if (result.IsCompleted == false) CallException(excExceptionConnectionLost); 
    Logger.Trace($"RAW: {BitConverter.ToString(asyncConnectionBuffer,0)}");
}

Код пишу в VS2019 v.16.4.4. Используется .net core 3.1. (на 2.2 те же проблемы) Тестирую работу в Win10 Pro и Ubuntu v.18.04 и v.19.10. Компилировал как в студии под Win так и непосредственно в Linux. (со всеми возможными опциями компиляции)

Суть проблемы: В Linux, при чтении ответа от железки последний байт её ответа теряется (вывод Wireshark):

Принятый пакет при просмотре в Wireshark.

Вывод лога:

Принятый пакет в выводе лога.

При следующем запросе, "потерянный байт" будет в начале принятых данных, а остальные байты дублируются из первого запроса:

Повторный запрос.

Хотя, на самом деле, железкой были отправлены такие данные:

Реальный ответ на второй запрос.

Послав третий запрос, мы получим корректный ответ на второй запрос.

Данная проблема встречается только в Linux (обоих версий), в Windows все работает отлично. Могу предположить, что проблема находится в runtime .net core, т.к. у нас есть софт, написанный на Java и крутящийся на сервере под Ubuntu 18.04, который успешно эти железки опрашивает и никаких проблем не испытывает.

Может кто сможет подсказать что дальше делать? Как донести эту проблему до Microsoft?

P.S. Полный лог Wireshark:

введите сюда описание изображения


Ответы (1 шт):

Автор решения: Dmitry

Как правильно подсказал Alex F, сообщения бились на несколько сегментов. Решением оказалось использование класса TcpClient, в нем, при чтении данных из потока, возвращается количество считанных байт. Сравнивая его с ожидаемым количеством, можно принять решение о дальнейшем чтении данных, примерно так:

int NumberOfbytes = stream.Read(data, 0, data.Length);
            ushort needBytes = BitConverter.ToUInt16(data, 4);
            needBytes = BitOperations.SwapTwoBytes(needBytes);
            needBytes += 6;
            if (NumberOfbytes < needBytes)
            {
                stream.Read(data, NumberOfbytes, needBytes - NumberOfbytes);
            }
→ Ссылка