Чтение и десериализация потока c # - PullRequest
3 голосов
/ 01 сентября 2011

У меня есть этот код:

public static List<ReplicableObject> ParseStreamForObjects(Stream stream) 
{
   List<ReplicableObject> result = new List<ReplicableObject>();
   while (true) 
   {
      // HERE I want to check that there's at least four bytes left in the stream
      BinaryReader br = new BinaryReader(stream);
      int length = br.ReadInt32();
      // HERE I want to check that there's enough bytes left in the stream
      byte[] bytes = br.ReadBytes(length);
      MemoryStream ms = new MemoryStream(bytes);
      ms.Position = 0;
      result.Add((ReplicableObject) Formatter.Deserialize(ms));
      ms.Close();
      br.Close();
   }
   return result;
}

К сожалению, объект потока всегда будет потоком TCP, что означает отсутствие операций поиска. Итак, как я могу проверить, чтобы убедиться, что я не перегружаю поток, в который я поместил комментарии // HERE?

Ответы [ 2 ]

3 голосов
/ 01 сентября 2011

Я не думаю, что есть какой-либо способ запросить NetworkStream, чтобы найти данные, которые вы ищете. Вероятно, вам нужно будет буферизовать любые данные, которые поток делает доступными, в другую структуру данных, а затем проанализировать объекты из этой структуры, как только вы узнаете, что в ней достаточно байтов.

Класс NetworkStream предоставляет свойство DataAvailable, которое сообщает вам, доступны ли для чтения какие-либо данные, а метод Read() возвращает значение, указывающее, сколько байтов фактически получено. Вы должны быть в состоянии использовать эти значения для выполнения необходимой буферизации.

2 голосов
/ 01 сентября 2011

См. Mr. Skeets page

Иногда вы заранее не знаете длину потока (например, сетевой поток) и просто хотите прочитатьвсе в буфер.Вот способ сделать это:

/// <summary>
/// Reads data from a stream until the end is reached. The
/// data is returned as a byte array. An IOException is
/// thrown if any of the underlying IO calls fail.
/// </summary>
/// <param name="stream">The stream to read data from</param>
public static byte[] ReadFully (Stream stream)
{
    byte[] buffer = new byte[32768];
    using (MemoryStream ms = new MemoryStream())
    {
        while (true)
        {
            int read = stream.Read (buffer, 0, buffer.Length);
            if (read <= 0)
                return ms.ToArray();
            ms.Write (buffer, 0, read);
        }
    }
}

Это должно дать вам несколько идей.Если у вас есть байтовый массив, проверить Length будет легко.

В вашем примере это будет выглядеть примерно так:

int bytes_to_read = 4;
byte[] length_bytes = new byte[bytes_to_read];
int bytes_read = stream.Read(length_bytes, 0, length_bytes.Length);
// Check that there's at least four bytes left in the stream
if(bytes_read != bytes_to_read) break;
int bytes_in_msg = BitConverter.ToInt32(length_bytes);
byte[] msg_bytes = new byte[bytes_in_msg];
bytes_read = stream.Read(msg_bytes, 0, msg_bytes.Length);
// Check that there's enough bytes left in the stream
if(bytes_read != bytes_in_msg ) break;
...
...