簡體   English   中英

C ++ / zlib / gzip壓縮和C#GZipStream解壓縮失敗

[英]C++/zlib/gzip compression and C# GZipStream decompression fails

我知道有很多關於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 *。 這是發送到上面的服務器以進行解壓縮的內容。

感謝你給與我的幫助! 另外,如果您需要更多信息,請與我們聯系。

CompressString函數中,返回從本地聲明的std::string獲取的char* 當函數返回時,該字符串將被銷毀,這將釋放您返回的指針的內存。

可能會將某些內容分配給此內存區域並在發送之前寫入壓縮數據。

您需要確保包含壓縮數據的內存在發送之前保持分配狀態。 也許通過將std::string&傳遞給函數並將其存儲在那里。

一個不相關的錯誤:你做char* outbuffer = new char[messageSize]; 但是沒有調用delete[]該緩沖區的delete[] 這將導致內存泄漏。 當您從此函數中拋出異常時,我建議使用std::unique_ptr<char[]>而不是嘗試使用您自己的delete[]調用手動對其進行排序。 事實上,我總是推薦std::unique_ptr而不是顯式調用delete如果可能的話。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM