gpt4 book ai didi

c# - 为什么我的 DeflateStream 无法通过 TCP 正确接收数据?

转载 作者:太空狗 更新时间:2023-10-29 21:32:46 26 4
gpt4 key购买 nike

我在本地计算机上的客户端和服务器设置上有一个 TcpClient 类。我一直在使用网络流来促进两者之间的成功来回通信。

展望 future ,我正尝试在通信中实现压缩。我试过 GZipStream 和 DeflateStream。我决定专注于 DeflateStream。但是,现在连接挂起而没有读取数据。

我尝试了 4 种不同的实现,但由于服务器端未读取传入数据和连接超时而全部失败。我将重点介绍我最近尝试过的两个实现,据我所知应该可行。

客户端分解为这个请求:有 2 个独立的实现,一个有 streamwriter,一个没有。

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 属性,它有一个 Available 属性。 MSDN 对可用属性说了这一点。

Gets the amount of data that has been received from the network and is available to be read.

在下面的调用之前 Available 是 77。读取 1 个字节后值为 0。

//receiveBufferSize = 1
int bytesIn = zippy.Read(receiveBuffer, 0, receiveBufferSize);

似乎没有任何关于 DeflateStream 消耗整个底层流的文档,我不知道为什么当有明确的调用来读取特定数量的字节时它会做这样的事情。

有谁知道为什么会发生这种情况,或者是否有办法保留基础数据以供将来读取?基于此“功能”和之前的 article that I read声明必须关闭 DeflateStream 才能完成发送(刷新将不起作用)似乎 DeflateStreams 在网络使用方面可能受到限制,特别是如果人们希望通过在接受完整流之前测试传入数据来对抗 DOS 攻击。

最佳答案

在查看您的代码时,我能想到的基本缺陷是对网络流和压缩工作方式的可能误解。

如果您继续使用一个 DeflateStream,我认为您的代码可能会工作。但是,您在快速阅读中使用了一个,然后创建了另一个。

我会试着用一个例子来解释我的推理。假设您有 8 个字节的原始数据要以压缩方式通过网络发送。现在让我们假设,原始数据的每个字节(8 位)都将以压缩形式压缩为 6 位。现在让我们看看您的代码对此做了什么。

从网络流中读取不到1个字节。你不能只拿 1 位。您可以使用 1 个字节、2 个字节或任意数量的字节,但不能使用位。

但是如果你只想接收原始数据的一个字节,你需要读取压缩数据的第一个完整字节。但是,只有 6 位压缩数据代表未压缩数据的第一个字节。第一个字节的最后 2 位用于原始数据的第二个字节。

现在如果你在那里切断流,网络流中剩下的是 5 个字节,它们没有任何意义,也无法解压缩。

deflate 算法比这更复杂,因此如果它不允许您在某一时刻停止从 NetworkStream 读取并从中间继续使用新的 DeflateStream,那么它是非常有意义的。为了将数据解压缩到它们的原始形式,必须存在解压缩的上下文。一旦你在快速阅读中处理了第一个 DeflateStream,这个上下文就消失了,你无法继续。

因此,要解决您的问题,请尝试只创建一个 DeflateStream 并将其传递给您的函数,然后将其处理掉。

关于c# - 为什么我的 DeflateStream 无法通过 TCP 正确接收数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35460378/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com