У меня есть приложение для Android Xamarin, которое захватывает h264-видеофрагменты с устройства Android 4.4 (KitKat) (оборудование x86) и отправляет их через TCP к клиенту Windows 10 (через WiFi). Я использую protobuf.net для упаковки фреймов с помощью SerializeWithLengthPrefix (Fixed32). Это работает очень часто, но случайным образом (между 20 секундами и 10 минутами) данные на стороне приема повреждаются. Вы можете видеть, что я также сохраняю данные на устройстве для отладки. Чтение этих данных с помощью клиентского приложения не вызывает ошибок (оно не повреждено). Я не понимаю, в чем проблема. Это похоже на ошибку платформы с TCP-клиентом Xamarin, но я с трудом верю, что я был бы единственным, у кого была эта проблема. Примечание. Компонент TCP работает в собственном потоке.TCP-данные от приложения Xamarin Android повреждены
private static void ProcessFrameQueue(TcpClient client)
{
//debug log for comparing TCP socket sent data with client recieved
_tempDumpFile = StreamControl.GetOutputTempFilePath(DateTime.Now.Ticks.ToString() + "-probuf-dump.bin");
var sentFrameCount = 0;
try
{
while (client.Client.IsConnected())
{
var data = _packetQueue.Take();
try
{
using (var stream = new MemoryStream())
{
Serializer.SerializeWithLengthPrefix(stream, data, PrefixStyle.Fixed32);
var protoBufData = stream.ToArray();
client.Client.Send(protoBufData);
//for debugging -- save the TCP data for comparison to what is recieved
//todo: delete as this is debuggng
using (var filestream = new FileStream(_tempDumpFile, FileMode.Append))
{
filestream.Write(protoBufData, 0, protoBufData.Length);
filestream.Flush(true);
}
}
sentFrameCount++;
}
catch (Exception ex)
{
//log error
}
} //end while
}
catch (Exception ex)
{
//log error
}
}
это простой клиент, я написал для отладки (я вручную расчета размера пакета, чтобы убедиться, что это не ошибка в protobuf.net - это не проблема protobuf.net). В конечном итоге пакет размера будет содержать плохие данные, приводящие к переполнению.
var client = new TcpClient("x.x.x.x", 19901);
client.ReceiveTimeout = 100000000;
byte[] bytes = new byte[client.ReceiveBufferSize];
var netStream = client.GetStream();
var sizezReadBtyes = 0;
var sizeBytes = new byte[4];
var packetCount = 0;
while (true)
{
//reads until it gets 4 bytes to calculate the packet size
var sizeOffset = 0;
var sizeLength = 4;
while ((sizezReadBtyes = netStream.Read(sizeBytes, sizeOffset, sizeLength)) > 0)
{
sizeOffset += sizezReadBtyes;
sizeLength -= sizezReadBtyes;
}
//read the remaining data...
var offset = 0;
var packetBytes = 0;
int packetlength = BitConverter.ToInt32(sizeBytes, 0);
var buffer = new byte[packetlength];
while (packetlength > 0 && (packetBytes = netStream.Read(buffer, offset, packetlength)) > 0)
{
offset += packetBytes;
packetlength -= packetBytes;
}
using (var ms = new MemoryStream(buffer))
{
var obj = ProtoBuf.Serializer.Deserialize<NetworkMediaPacket>(ms);
Console.WriteLine($"packet found {packetCount++} {obj.Data.Length}");
}
if (packetlength > 0) throw new EndOfStreamException();
}
Вы уверены, что 'while ((readBtyes = netStream.Read (sizeBytes, 0, 4))> 0)' всегда читает 4 байта? потому что вы проверяете только '> 0'. Вы можете создать небольшое время для чтения заголовка' Fixed32'. –
@JeroenvanLangen Спасибо за предложение. Я добавил проверку на чтение размера (см. Пример клиента), но все равно приводит к прерывистым ошибкам. Кроме того, этот код является просто альтернативой ProtoBuf.Serializer.DeserializeWithLengthPrefix, который также потерпел неудачу. –
больше копания указывает, что пакеты иногда перезаписываются следующим пакетом в потоке. Я использовал пакеты, заполненные нулевыми значениями (вместо обычной полезной нагрузки). поэтому теперь я могу видеть, как следующий заголовок пакета вставлен внутри полезной нагрузки предыдущего пакета. –