我有一对使用网络流进行通信的 C# 客户端-服务器程序。 一切正常,因为没有压缩。 现在我想降低带宽使用量,因此我想在我的网络流周围使用压缩包装流。
我尝试过 SharpZipLib、DotNetZip、C# 自己的 GZipStream - 但我无法让它们工作。
SharpZipLib 在刷新和应用此处指定的修复时出现问题:http://community.sharpdevelop.net/forums/p/7855/22139.aspx导致异常“ header 校验和非法”。
使用 DotNetZip 的 DeflateStream 会导致 ZLibException(“错误状态(无效的存储 block 长度)”);
GZipStream 给了我一个 System.IO.InvalidDataException ,指出“GZip header 中的魔数(Magic Number)不正确。确保您传递的是 GZip 流。”。
我实现它的方式是,每当我的框架必须发送字节数组时,我都会围绕现有网络流创建一个新的压缩流包装器,将字节写入压缩流,然后刷新,关闭并丢弃它。 这是为了确保每个 WriteMessage(byte[] blah) 使用它自己的状态无关的压缩流,该压缩流将立即刷新。 我小心翼翼地不让任何流关闭原始网络流。
using (System.IO.Stream outputStream = CreateOutputStreamWrapper(_networkStream))
{
outputStream.Write(messageBytes, 0, messageBytes.Length);
outputStream.Flush();
outputStream.Close();
outputStream.Dispose();
}
基本上,我的 DecompressionStream 创建如下(可选注释掉)
protected System.IO.Stream CreateInputStreamWrapper(System.IO.Stream inInputStream)
{
//return new DeflateStream(inInputStream, CompressionMode.Decompress, true);
//return new BZip2InputStream(inInputStream, true);
return new GZipStream(inInputStream, System.IO.Compression.CompressionMode.Decompress, true);
}
开始为
_inputStream.BeginRead(_buffer, 0, _buffer.Length, new AsyncCallback(ReceiveCallback), null);
然后在 ReceiveCallback 中,读取数据,刷新流,关闭并处置:
//Get received bytes count
var bytesRead = _inputStream.EndRead(ar);
_inputStream.Flush();
_inputStream.Close();
_inputStream.Dispose();
并立即通过再次调用CreateInputStreamWrapper创建一个新的inputStream。
所以这是怎么回事? 由于所有压缩流实现都因错误而失败,这些错误归结为“数据流中存在错误”,我有一种预感,这一定是我和我的代码。 另一方面,如果我删除压缩并仅使用网络流,则没有问题,这让我认为问题一定出在压缩代码上。
这听起来熟悉吗? 当我们这样做时,有谁知道任何(其他)压缩流实现适合环绕网络流?
最佳答案
以防万一其他人读过本文,DotNetZip 的 ZLib 流有一个 FlushMode 标志,使您能够为网络内容设置刷新兼容(“同步”和“完整”模式)。
关于C# 网络流压缩 - Sharpziplib、DotNetZip、gzipstream 在我的流上均出现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9660009/