2016-09-26 4 views
1

У меня есть приложение для 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(); 

     } 
+0

Вы уверены, что 'while ((readBtyes = netStream.Read (sizeBytes, 0, 4))> 0)' всегда читает 4 байта? потому что вы проверяете только '> 0'. Вы можете создать небольшое время для чтения заголовка' Fixed32'. –

+0

@JeroenvanLangen Спасибо за предложение. Я добавил проверку на чтение размера (см. Пример клиента), но все равно приводит к прерывистым ошибкам. Кроме того, этот код является просто альтернативой ProtoBuf.Serializer.DeserializeWithLengthPrefix, который также потерпел неудачу. –

+0

больше копания указывает, что пакеты иногда перезаписываются следующим пакетом в потоке. Я использовал пакеты, заполненные нулевыми значениями (вместо обычной полезной нагрузки). поэтому теперь я могу видеть, как следующий заголовок пакета вставлен внутри полезной нагрузки предыдущего пакета. –

ответ

1

Я смог исправить удаление моей блокирующей очереди (_packetQueue). Я просто использовал writeasync для TCPClient NetStream. Это выглядит как ошибка в коде Xamarin/Mono/.net.

Смежные вопросы