Неверное количество считываемых данных из 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):
Вывод лога:
При следующем запросе, "потерянный байт" будет в начале принятых данных, а остальные байты дублируются из первого запроса:
Хотя, на самом деле, железкой были отправлены такие данные:
Послав третий запрос, мы получим корректный ответ на второй запрос.
Данная проблема встречается только в Linux (обоих версий), в Windows все работает отлично. Могу предположить, что проблема находится в runtime .net core, т.к. у нас есть софт, написанный на Java и крутящийся на сервере под Ubuntu 18.04, который успешно эти железки опрашивает и никаких проблем не испытывает.
Может кто сможет подсказать что дальше делать? Как донести эту проблему до Microsoft?
P.S. Полный лог Wireshark:
Ответы (1 шт):
Как правильно подсказал 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);
}




