#c# #stream #networkstream
#c# #поток #networkstream
Вопрос:
У меня есть клиент-серверное приложение, в котором сервер передает 4-байтовое целое число, указывающее, насколько большой будет следующая передача. Когда я считываю 4-байтовое целое число на стороне клиента (указывая FILE_SIZE), при следующем чтении потока я получаю FILE_SIZE 4 прочитанных байта.
Нужно ли указывать смещение на 4 при чтении из этого потока, или есть способ автоматического продвижения сетевого потока, чтобы мое смещение всегда могло быть 0?
СЕРВЕР
NetworkStream theStream = theClient.getStream();
//...
//Calculate file size with FileInfo and put into byte[] size
//...
theStream.Write(size, 0, size.Length);
theStream.Flush();
КЛИЕНТ
NetworkStream theStream = theClient.getStream();
//read size
byte[] size = new byte[4];
int bytesRead = theStream.Read(size, 0, 4);
...
//read content
byte[] content = new byte[4096];
bytesRead = theStream.Read(content, 0, 4096);
Console.WriteLine(bytesRead); // <-- Prints filesize 4
Комментарии:
1. Что такое
filesize
? Это то жеsize.Length
самое, что и?2. Вы уверены , что
size.Length
(на стороне сервера) равно 4? (И что вы не считываете размер следующего файла при этом втором чтении на стороне клиента?)3. Что такое размер? То, что вы делаете, будет нестабильным. Вместо этого используйте BinaryReader / BinaryWriter с ReadInt32 / WriteInt32, чтобы избежать проблем с размерами.
4.
NetworkStream
не поддерживает произвольный доступ к сетевому потоку данных. Значение свойства CanSeek, которое указывает, поддерживает ли поток поиск, всегда равно false; чтение свойства Position, чтение свойства Length или вызов метода Seek вызовет исключение NotSupportedException. — Из MSDN . Возможно, вы можете прочитать поток и отбросить первые 4 байта при чтении содержимого?5. размер — это байт [], полученный с помощью BitConverter. getBytes(FileInfo. Длина); где FileInfo = новый FileInfo(myFileName);
Ответ №1:
Правильно; нашел это; FileInfo.Length
это long
; ваш вызов:
binWrite.Write(fileInfo.Length);
записывает 8 байт, с небольшим порядковым номером. Затем вы читаете это обратно через:
filesize = binRead.ReadInt32();
какой порядковый номер даст вам то же значение (по крайней мере, для 32 бит). 00
Однако в потоке осталось неиспользованным 4 байта (из старших байтов long
) — отсюда и несоответствие в 4 байта.
Используйте один из:
binWrite.Write((int)fileInfo.Length);
filesize = binRead.ReadInt64();
Ответ №2:
NetworkStream
конечно, продвигается, но в обоих случаях ваше чтение ненадежно; классическое «чтение известного объема содержимого» было бы:
static void ReadAll(Stream source, byte[] buffer, int bytes) {
if(bytes > buffer.Length) throw new ArgumentOutOfRangeException("bytes");
int bytesRead, offset = 0;
while(bytes > 0 amp;amp; (bytesRead = source.Reader(buffer, offset, bytes)) > 0) {
offset = bytesRead;
bytes -= bytesRead;
}
if(bytes != 0) throw new EndOfStreamException();
}
с:
ReadAll(theStream, size, 4);
...
ReadAll(theStream, content, contentLength);
также обратите внимание, что вам нужно быть осторожным с порядковым номером при разборе длины-префикса.
Я подозреваю, что вы просто не читаете полные данные.
Комментарии:
1. @aloneguid ОП использует a
Stream
, и лично я предпочитаю избегатьBinaryReader
(но тогда я, как правило, очень разборчив в своей кодировке)2. BinaryReader принимает поток в конструкторе, а также исходную кодировку. В чем причина, чтобы избежать этого?
3. @aloneguid в основном потому, что для того, что я делаю, это не добавляет ничего полезного. Единственным предельным случаем является «чтение известного объема содержимого», что тривиально для воспроизведения. Кроме того, операции чтения / записи не обязательно согласуются с вашим требуемым форматом данных (особенно, но не только, в отношении порядкового номера). Для контекста я поддерживаю библиотеку двоичной сериализации OSS с очень специфической кодировкой, которая просто не
BinaryReader
очень хорошо соответствует; p4. это только в вашем конкретном случае, я думаю, BinaryXXX это экономит несколько ночей при написании двоичного протокола с нуля, C # с обеих сторон 😉
5. @aloneguid если бы целью было сэкономить несколько ночей, лучшим вариантом было бы: использовать предварительно свернутую библиотеку двоичной сериализации; p (за исключением, может быть, моих ночей …)