2

我有一对使用网络流进行通信的 C# 客户端-服务器程序。一切正常,因为它没有压缩。现在我想降低带宽使用率,所以我想在我的网络流周围使用压缩包装流。

我已经尝试过 SharpZipLib、DotNetZip、C# 自己的 GZipStream——但我无法让它们中的任何一个工作。

SharpZipLib 有刷新问题,并应用此处指定的修复:http: //community.sharpdevelop.net/forums/p/7855/22139.aspx导致异常“标题校验和非法”。

使用 DotNetZip 的 DeflateStream 会导致 ZLibException("Bad state (invalid stored block lengths)");

GZipStream 给了我一个 System.IO.InvalidDataException 说明“GZip 标头中的幻数不正确。确保您传递的是 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。

发生什么了 ?由于所有压缩流实现都失败,错误归结为“数据流中有错误”,我有一种预感,一定是我和我的代码。另一方面,如果我删除压缩并只使用网络流就没有问题,这让我认为问题一定出在压缩代码上。

这听起来很熟悉吗?当我们在做的时候,有没有人知道任何(其他)适合环绕网络流的压缩流实现?

4

1 回答 1

4

以防万一其他人读过这篇文章,DotNetZip 的 ZLib 流有一个 FlushMode 标志,使您能够设置与网络内容兼容的刷新(“同步”和“完整”模式)。

于 2012-03-13T08:26:48.297 回答