C++/zlib/gzip压缩和C#GZipStream解压缩失败

本文关键字:C#GZipStream 解压缩 失败 压缩 zlib gzip C++ | 更新日期: 2023-09-27 18:27:35

我知道有很多关于zlib/gzip等的问题,但没有一个与我想要做的完全匹配(或者至少我还没有找到)。作为一个快速的概述,我有一个C#服务器,它使用GZipStream来解压缩传入的字符串。我的任务是编写一个C++客户端,它将压缩与GZipStream解压缩兼容的字符串。

当我使用下面的代码时,我会收到一个错误,上面写着"GZip标头中的幻数不正确。请确保你正在传递GZip流。"我知道幻数是什么,我只是不知道如何正确地设置它。

最后,我使用的是C++zlib-nuget包,但也使用了直接来自zlib的源文件,同样运气不好。

下面是一个更深入的视图:

服务器的解压缩功能

public static string ReadMessage(NetworkStream stream)
    {
        byte[] buffer = new byte[512];
        StringBuilder messageData = new StringBuilder();
        GZipStream gzStream = new GZipStream(stream, CompressionMode.Decompress, true);
        int bytes = 0;
        while (true)
        {
            try
            {
                bytes = gzStream.Read(buffer, 0, buffer.Length);
            }
            catch (InvalidDataException ex)
            {
                Console.WriteLine($"Busted: {ex.Message}");
                return "";
            }
            // Use Decoder class to convert from bytes to Default
            // in case a character spans two buffers.
            Decoder decoder = Encoding.Default.GetDecoder();
            char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
            decoder.GetChars(buffer, 0, bytes, chars, 0);
            messageData.Append(chars);
            Console.WriteLine(messageData);
            // Check for EOF or an empty message.
            if (messageData.ToString().IndexOf("<EOF>", StringComparison.Ordinal) != -1)
                break;
        }
        int eof = messageData.ToString().IndexOf("<EOF>", StringComparison.Ordinal);
        string message = messageData.ToString().Substring(0, eof).Trim();
        //Returns message without ending EOF
        return message;
    }

总之,它在中接受NetworkStream,获取压缩的字符串,对其进行解压缩,将其添加到字符串中,并循环直到找到被删除的<EOF>,然后返回最终解压缩的字符串。这几乎与MSDN的示例相匹配。

这是C++客户端代码:

char* CompressString(char* message)
{
    int messageSize = sizeof(message);
    //Compress string
    z_stream zs;
    memset(&zs, 0, sizeof(zs));
    zs.zalloc = Z_NULL;
    zs.zfree = Z_NULL;
    zs.opaque = Z_NULL;
    zs.next_in = reinterpret_cast<Bytef*>(message);
    zs.avail_in = messageSize;
    int iResult = deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, (MAX_WBITS + 16), 8, Z_DEFAULT_STRATEGY);
    if (iResult != Z_OK) zerr(iResult);
    int ret;
    char* outbuffer = new char[messageSize];
    std::string outstring;
    // retrieve the compressed bytes blockwise
    do {
        zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
        zs.avail_out = sizeof(outbuffer);
        ret = deflate(&zs, Z_FINISH);
        if (outstring.size() < zs.total_out) {
            // append the block to the output string
            outstring.append(outbuffer,
            zs.total_out - outstring.size());
        }
    } while (ret == Z_OK);
    deflateEnd(&zs);
    if (ret != Z_STREAM_END) {          // an error occurred that was not EOF
        std::ostringstream oss;
        oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
        throw std::runtime_error(oss.str());
    }
    return &outstring[0u];
}

长话短说,它接受一个字符串,并通过一个非常标准的zlib压缩,WBITS被设置为将其封装在一个gzip页眉/页脚中。然后返回压缩输入的char*。这是发送到上面的服务器进行解压缩的内容。

谢谢你能给我的任何帮助!此外,如果您需要更多信息,请告诉我。

C++/zlib/gzip压缩和C#GZipStream解压缩失败

CompressString函数中,返回从本地声明的std::string获得的char*。当函数返回时,字符串将被销毁,这将释放您返回的指针处的内存。

很可能有一些东西被分配到这个内存区域,并在发送压缩数据之前将其写入。

您需要确保包含压缩数据的内存在发送之前保持分配状态。也许是通过将std::string&传递到函数中并将其存储在其中。

一个无关的错误:您执行char* outbuffer = new char[messageSize];,但该缓冲区没有对delete[]的调用。这将导致内存泄漏。由于您也从该函数抛出异常,我建议您使用std::unique_ptr<char[]>,而不是尝试使用自己的delete[]调用手动排序。事实上,如果可能的话,我总是建议使用std::unique_ptr,而不是显式调用delete