2013-10-15 5 views
2

Я хотел бы иметь возможность получить длину данных, доступных из сетевого потока TCP в C#, чтобы установить размер буфера перед чтением из сетевого потока. Существует свойство NetworkStream.Length, но оно еще не реализовано, и я не хочу выделять огромный размер для буфера, так как это займет слишком много места. Единственный способ сделать это - это предшествовать передаче данных другим, указав размер, но это кажется немного грязным. Что было бы лучшим способом для меня сделать это.Получить длину данных, доступных в NetworkStream

+0

Обычный способ чтения потока состоит в том, чтобы делать это небольшими порциями за один раз (например, 512 байт), а когда '0' возвращается из метода' Read', это означает, что данных больше нет. Есть ли причина, по которой вы этого не делаете, или вы не знали об этом? –

+0

Я не знал, не могли бы вы привести небольшой пример кода? Если вы опубликуете его как ответ, я, скорее всего, его приму. –

+0

Другой метод заключается в том, чтобы сохранить длину сообщения перед данными сообщения. Затем зачитайте, например, длину в четыре байта, затем переведите четыре байта в целое число и прочитайте до этого количества байтов. –

ответ

8

При обращении к Streams вы обычно читаете и записываете данные в небольших кусках (например, килобайт или около того) или используете такой метод, как CopyTo, который делает это за вас.

Это пример использования CopyTo для копирования содержимого потока в другой поток и возврата его в виде byte[] из метода с использованием буфера с автоматическим размером.

using (MemoryStream ms = new MemoryStream()) 
{ 
    networkStream.CopyTo(ms); 
    return ms.ToArray(); 
} 

Это код, который считывает данные таким же образом, но более вручную, что может быть лучше для вас, чтобы работать, в зависимости от того, что вы делаете с данными:

byte[] buffer = new byte[2048]; // read in chunks of 2KB 
int bytesRead; 
while((bytesRead = networkStream.Read(buffer, 0, buffer.Length)) > 0) 
{ 
    //do something with data in buffer, up to the size indicated by bytesRead 
} 

(основа для этих фрагментов кода исходила от Most efficient way of reading data from a stream)

+0

Это замечательно! Я буду использовать это для записи в поток памяти, пока все данные не поступят. –

+0

Я на самом деле немного изменил ваш код, чтобы убедиться, что у меня есть весь объект, прежде чем продолжить, по сути, первые 8 байтов пакета - это размер, и он продолжит читать то, что может, пока не будет иметь такое же количество байтов в памяти, как и ожидалось. –

0

Не существует внутренней длины сетевого потока. Вам придется либо отправить длину данных, чтобы следовать с другого конца, либо прочитать все входящие данные в другой поток, где вы можете получить доступ к информации о длине.

2

Дело в том, что вы действительно не можете быть уверены, что все данные считываются сокет, но в любое время может появиться больше данных. Это попытка, даже если вы как-то знаете, сколько данных ожидать, скажем, если у вас есть заголовок пакета, который содержит длину. весь пакет еще не получен.

Если вы читаете произвольные данные (например, файл), у вас должен быть буфер разумного размера (например, 1k-10k или что-то, что вы считаете оптимальным для вашего сценария), а затем записывать данные в файл как его чтение из потока.

var buffer = byte[1000]; 
var readBytes = 0; 
using(var netstream = GetTheStreamSomhow()){ 
    using(var fileStream = (GetFileStreamSomeHow())){ 
     while(netstream.Socket.Connected) //determine if there is more data, here we read until the socket is closed 
     { 
      readBytes = netstream.Read(buffer,0,buffer.Length); 
      fileStrem.Write(buffer,0,buffer.Length); 
     } 
    } 
} 

Или просто использовать CopyTo как Тим предложил :) Просто убедитесь, что все данные действительно были считаны, в том числе данные, которые не получили по сети еще.

0

Сначала вы можете отправить длину входящих данных. Например: У вас есть data = byte[16], которую вы хотите отправить. Поэтому сначала вы отправляете 16 и определяете на сервере, что эта длина всегда 2 (потому что 16 имеет два символа). Теперь вы знаете, что incomingLength = 16. Теперь вы можете подождать данные по длине incomingLength.