У меня есть класс TcpClient для настройки клиента и сервера на моей локальной машине. Я использую сетевой поток для облегчения обмена данными между ними.
Двигаясь вперед, я пытаюсь реализовать сжатие в сообщениях. Я пробовал GZipStream и DeflateStream. Я решил сосредоточиться на DeflateStream. Однако сейчас соединение зависает без чтения данных.
Я пробовал 4 разных реализации, и все они потерпели неудачу из-за того, что серверная сторона не читала входящие данные и истекло время ожидания соединения. Я сосредоточусь на двух реализациях, которые я пробовал совсем недавно, и, насколько мне известно, они должны работать.
Клиент разбит на этот запрос: есть 2 отдельные реализации, одна со стримрайтером, другая без.
textToSend = ENQUIRY + START_OF_TEXT + textToSend + END_OF_TEXT;
// Send XML Request
byte[] request = Encoding.UTF8.GetBytes(textToSend);
using (DeflateStream streamOut = new DeflateStream(netStream, CompressionMode.Compress, true))
{
//using (StreamWriter sw = new StreamWriter(streamOut))
//{
// sw.Write(textToSend);
// sw.Flush();
streamOut.Write(request, 0, request.Length);
streamOut.Flush();
//}
}
Сервер получает запрос, и я делаю
1.) быстрое чтение первого символа, затем, если он соответствует тому, что я ожидаю
2.) я продолжаю читать остальные.
Первое чтение работает правильно, и если я хочу прочитать весь поток, все это есть. Однако я хочу только прочитать первый символ и оценить его, а затем продолжить в своем методе LongReadStream.
Когда я пытаюсь продолжить чтение потока, данные для чтения отсутствуют. Я предполагаю, что данные теряются при первом чтении, но я не уверен, как это определить. Весь этот код работает правильно, когда я использую обычный NetworkStream.
Вот код на стороне сервера.
private void ProcessRequests()
{
// This method reads the first byte of data correctly and if I want to
// I can read the entire request here. However, I want to leave
// all that data until I want it below in my LongReadStream method.
if (QuickReadStream(_netStream, receiveBuffer, 1) != ENQUIRY)
{
// Invalid Request, close connection
clientIsFinished = true;
_client.Client.Disconnect(true);
_client.Close();
return;
}
while (!clientIsFinished) // Keep reading text until client sends END_TRANSMISSION
{
// Inside this method there is no data and the connection times out waiting for data
receiveText = LongReadStream(_netStream, _client);
// Continue talking with Client...
}
_client.Client.Shutdown(SocketShutdown.Both);
_client.Client.Disconnect(true);
_client.Close();
}
private string LongReadStream(NetworkStream stream, TcpClient c)
{
bool foundEOT = false;
StringBuilder sbFullText = new StringBuilder();
int readLength, totalBytesRead = 0;
string currentReadText;
c.ReceiveBufferSize = DEFAULT_BUFFERSIZE * 100;
byte[] bigReadBuffer = new byte[c.ReceiveBufferSize];
while (!foundEOT)
{
using (var decompressStream = new DeflateStream(stream, CompressionMode.Decompress, true))
{
//using (StreamReader sr = new StreamReader(decompressStream))
//{
//currentReadText = sr.ReadToEnd();
//}
readLength = decompressStream.Read(bigReadBuffer, 0, c.ReceiveBufferSize);
currentReadText = Encoding.UTF8.GetString(bigReadBuffer, 0, readLength);
totalBytesRead += readLength;
}
sbFullText.Append(currentReadText);
if (currentReadText.EndsWith(END_OF_TEXT))
{
foundEOT = true;
sbFullText.Length = sbFullText.Length - 1;
}
else
{
sbFullText.Append(currentReadText);
}
// Validate data code removed for simplicity
}
c.ReceiveBufferSize = DEFAULT_BUFFERSIZE;
c.ReceiveTimeout = timeOutMilliseconds;
return sbFullText.ToString();
}
private string QuickReadStream(NetworkStream stream, byte[] receiveBuffer, int receiveBufferSize)
{
using (DeflateStream zippy = new DeflateStream(stream, CompressionMode.Decompress, true))
{
int bytesIn = zippy.Read(receiveBuffer, 0, receiveBufferSize);
var returnValue = Encoding.UTF8.GetString(receiveBuffer, 0, bytesIn);
return returnValue;
}
}
EDIT NetworkStream имеет базовое свойство Socket, которое имеет свойство Available. MSDN говорит об этом о доступном свойстве.
Получает объем данных, полученных из сети и доступных для чтения.
Перед вызовом ниже Доступно 77. После чтения 1 байта значение равно 0.
//receiveBufferSize = 1
int bytesIn = zippy.Read(receiveBuffer, 0, receiveBufferSize);
Кажется, нет никакой документации о том, что DeflateStream потребляет весь базовый поток, и я не знаю, почему он делает это, когда есть явные вызовы для чтения определенного количества байтов.
Кто-нибудь знает, почему это происходит, или есть ли способ сохранить базовые данные для чтения в будущем? Основываясь на этой «функции» и предыдущей статье, которую я прочитал, DeflateStream должен быть закрыт, чтобы завершить отправку (flush не будет работать). Похоже, DeflateStreams может быть ограничен в использовании для работы в сети, особенно если кто-то хочет противостоять DOS-атакам, проверяя входящие данные, прежде чем принимать полный поток.