我在本地机器上的客户端和服务器设置上有一个 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;
}
}
编辑 NetworkStream 有一个基础的 Socket 属性,它有一个可用的属性。MSDN 对可用属性进行了说明。
获取已从网络接收并可供读取的数据量。
在调用之前可用是 77。读取 1 个字节后,值是 0。
//receiveBufferSize = 1
int bytesIn = zippy.Read(receiveBuffer, 0, receiveBufferSize);
似乎没有任何关于 DeflateStream 消耗整个底层流的文档,我不知道为什么当有明确的调用来读取特定数量的字节时它会做这样的事情。
有谁知道为什么会发生这种情况,或者是否有办法保留基础数据以供将来阅读?基于这个“功能”和我读过的一篇文章,说明必须关闭 DeflateStream 才能完成发送(刷新不起作用),似乎 DeflateStreams 在网络使用方面可能受到限制,特别是如果希望通过测试来对抗 DOS 攻击接受完整流之前的传入数据。