- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在本地计算机上的客户端和服务器设置上有一个 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/
我通过 spring ioc 编写了一些 Rest 应用程序。但我无法解决这个问题。这是我的异常(exception): org.springframework.beans.factory.BeanC
我对 TestNG、Spring 框架等完全陌生,我正在尝试使用注释 @Value通过 @Configuration 访问配置文件注释。 我在这里想要实现的目标是让控制台从配置文件中写出“hi”,通过
为此工作了几个小时。我完全被难住了。 这是 CS113 的实验室。 如果用户在程序(二进制计算器)结束时选择继续,我们需要使用 goto 语句来到达程序的顶部。 但是,我们还需要释放所有分配的内存。
我正在尝试使用 ffmpeg 库构建一个小的 C 程序。但是我什至无法使用 avformat_open_input() 打开音频文件设置检查错误代码的函数后,我得到以下输出: Error code:
使用 Spring Initializer 创建一个简单的 Spring boot。我只在可用选项下选择 DevTools。 创建项目后,无需对其进行任何更改,即可正常运行程序。 现在,当我尝试在项目
所以我只是在 Mac OS X 中通过 brew 安装了 qt。但是它无法链接它。当我尝试运行 brew link qt 或 brew link --overwrite qt 我得到以下信息: ton
我在提交和 pull 时遇到了问题:在提交的 IDE 中,我看到: warning not all local changes may be shown due to an error: unable
我跑 man gcc | grep "-L" 我明白了 Usage: grep [OPTION]... PATTERN [FILE]... Try `grep --help' for more inf
我有一段代码,旨在接收任何 URL 并将其从网络上撕下来。到目前为止,它运行良好,直到有人给了它这个 URL: http://www.aspensurgical.com/static/images/a
在过去的 5 个小时里,我一直在尝试在我的服务器上设置 WireGuard,但在完成所有设置后,我无法 ping IP 或解析域。 下面是服务器配置 [Interface] Address = 10.
我正在尝试在 GitLab 中 fork 我的一个私有(private)项目,但是当我按下 fork 按钮时,我会收到以下信息: No available namespaces to fork the
我这里遇到了一些问题。我是 node.js 和 Rest API 的新手,但我正在尝试自学。我制作了 REST API,使用 MongoDB 与我的数据库进行通信,我使用 Postman 来测试我的路
下面的代码在控制台中给出以下消息: Uncaught DOMException: Failed to execute 'appendChild' on 'Node': The new child el
我正在尝试调用一个新端点来显示数据,我意识到在上一组有效的数据中,它在数据周围用一对额外的“[]”括号进行控制台,我认为这就是问题是,而新端点不会以我使用数据的方式产生它! 这是 NgFor 失败的原
我正在尝试将我的 Symfony2 应用程序部署到我的 Azure Web 应用程序,但遇到了一些麻烦。 推送到远程时,我在终端中收到以下消息 remote: Updating branch 'mas
Minikube已启动并正在运行,没有任何错误,但是我无法 curl IP。我在这里遵循:https://docs.traefik.io/user-guide/kubernetes/,似乎没有提到关闭
每当我尝试docker组成任何项目时,都会出现以下错误。 我尝试过有和没有sudo 我在这台机器上只有这个问题。我可以在Mac和Amazon WorkSpace上运行相同的容器。 (myslabs)
我正在尝试 pip install stanza 并收到此消息: ERROR: No matching distribution found for torch>=1.3.0 (from stanza
DNS 解析看起来不错,但我无法 ping 我的服务。可能是什么原因? 来自集群中的另一个 Pod: $ ping backend PING backend.default.svc.cluster.l
我正在使用Hibernate 4 + Spring MVC 4当我开始 Apache Tomcat Server 8我收到此错误: Error creating bean with name 'wel
我是一名优秀的程序员,十分优秀!