亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在 Go 中解碼 zlib 流?

如何在 Go 中解碼 zlib 流?

Go
慕容森 2022-10-24 09:39:32
問題是什么?我無法使用 go 的zlib包從 zlib 流中解碼有效的壓縮塊。我準備了一個 github 存儲庫,其中包含說明我遇到的問題的代碼和數據:https ://github.com/andreyst/zlib-issue 。那些塊是什么?它們是由文本游戲服務器 (MUD) 生成的消息。該游戲服務器以多個塊發送壓縮的消息流,其中第一個包含 zlib 標頭,其他不包含。我使用名為“mcclient”的代理捕獲了兩個塊(第一個和第二個),它是一個邊車,為不支持壓縮的 MUD 客戶端提供壓縮。它是用 C 語言編寫的,并使用 Czlib庫來解碼壓縮塊。塊包含在“塊”目錄中,并以數字0和1. *.in文件包含壓縮數據。*.out包含從 mcclient 捕獲的未壓縮數據。*.log包含 zlib 解壓的狀態(inflate調用的返回碼)。一個特殊的all.in塊是與塊0連接的塊1。為什么我認為它們是有效的?mcclient使用 C 成功解壓縮輸入塊,zlib沒有任何問題。*.logstatus 顯示0這意味著 Z_OK 這意味著 zlib 用語中沒有錯誤。zlib-flate -uncompress < chunks/all.in在 Linux 下可以正常工作并解壓縮為相同的內容。在 Mac OS 下,它也解壓縮到相同的內容,但帶有警告zlib-flate: WARNING: zlib code -5, msg = input stream is complete but output may still be valid——這看起來與預期的一樣,因為塊不包含“官方”流結束。中的 Python 代碼decompress.py可以正確解壓縮all.in和0/1塊,沒有任何問題。go的zlib有什么問題?看main.go——它嘗試解壓縮這些塊,從開始然后all.in嘗試逐步解壓縮塊。01嘗試 decode all.in( func all()) 有點成功,至少解壓后的數據是一樣的,但是 zlib reader 返回 error flate: corrupt input before offset 446。在嘗試逐塊解壓縮塊的實際場景(func stream())時,zlib 讀取器使用預期數據解碼第一個塊,但返回錯誤flate: corrupt input before offset 32,隨后嘗試解碼塊1完全失敗。問題zlib是否可以在適合這種場景的某種“流”模式下使用 go 的包?也許我使用不正確?如果沒有,解決方法是什么?同樣有趣的是,為什么會這樣——這是設計使然嗎?只是還沒有實施嗎?我錯過了什么?
查看完整描述

2 回答

?
江戶川亂折騰

TA貢獻1851條經驗 獲得超5個贊

請注意,錯誤表示輸入后偏移處的數據已損壞。那是因為您從文件中讀取的方式:


    buf := make([]byte, 100000)

    n, readErr := f.Read(buf)

    if readErr != nil {

        log.Fatalf("readErr=%v\n", readErr)

    }

    fmt.Printf("Read bytes, n=%v\n", n)


    buffer := bytes.NewBuffer(buf)

    zlibReader, zlibErr := zlib.NewReader(buffer)

    if zlibErr != nil {

        log.Fatalf("zlibErr=%v\n", zlibErr)

    }

buf := make([]byte, 100000)將制作一個 100000 字節的切片,全部為 0。但在all.in. 由于您從不縮短切片,因此閱讀器將在有效數據之后遇到幾千個零并斷定它已損壞。這就是你得到輸出和錯誤的原因。


至于流媒體。在 TCP/UDP 連接的情況下,您應該能夠將 a 連接傳遞io.Reader給zlib.NewReader. 為了模擬相同的內容,我在修改后的代碼中使用了io.Pipe:


package main


import (

    "bytes"

    "compress/zlib"

    "fmt"

    "io"

    "log"

    "os"


    otherzlib "github.com/4kills/go-zlib"

)


func main() {

    all()

    stream()


    // Alas it hangs :(

    // otherZlib()

}


func all() {

    fmt.Println("==== RUNNING DECOMPRESSION OF all.in")

    fmt.Println("")


    buf, readErr := os.ReadFile("./chunks/all.in")

    if readErr != nil {

        log.Fatalf("readErr=%v\n", readErr)

    }

    fmt.Printf("Read bytes, n=%v\n", len(buf))


    buffer := bytes.NewBuffer(buf)

    zlibReader, zlibErr := zlib.NewReader(buffer)

    if zlibErr != nil {

        log.Fatalf("zlibErr=%v\n", zlibErr)

    }


    out := new(bytes.Buffer)

    written, copyErr := io.Copy(out, zlibReader)

    if copyErr != nil {

        log.Printf("copyErr=%v\n", copyErr)

    }

    fmt.Printf("Written bytes, n=%v, out:\n%v\n", written, out.String())

    fmt.Println("")

}


func stream() {

    fmt.Println("==== RUNNING DECOMPRESSION OF SEPARATE CHUNKS")

    fmt.Println("")


    pRead, pWrite := io.Pipe()

    go func() {

        buf, readErr := os.ReadFile("./chunks/0.in")

        if readErr != nil {

            log.Fatalf("readErr=%v\n", readErr)

        }

        fmt.Printf("Read 0 bytes, n=%v\n", len(buf))


        written0, copy0Err := io.Copy(pWrite, bytes.NewBuffer(buf))

        if copy0Err != nil {

            log.Printf("copy0Err=%v\n", copy0Err)

        }

        fmt.Printf("Written compressed bytes, n0=%v", written0)


        buf, readErr = os.ReadFile("./chunks/1.in")

        if readErr != nil {

            log.Fatalf("read1Err=%v\n", readErr)

        }

        fmt.Printf("Read 1 bytes, n=%v\n", len(buf))


        written1, copy1Err := io.Copy(pWrite, bytes.NewBuffer(buf))

        if copy1Err != nil {

            log.Printf("copy1Err=%v\n", copy1Err)

        }

        fmt.Printf("Written compressed bytes, n1=%v", written1)


        pWrite.Close()

    }()


    zlibReader, zlibErr := zlib.NewReader(pRead)

    if zlibErr != nil {

        log.Fatalf("zlibErr=%v\n", zlibErr)

    }


    out := new(bytes.Buffer)

    written2, copy2Err := io.Copy(out, zlibReader)

    if copy2Err != nil {

        log.Printf("copy2Err=%v\n", copy2Err)

    }

    fmt.Printf("Written decompressed bytes, n0=%v, out:\n%v\n", written2, out.String())


    fmt.Println("")

}

使用此代碼,我沒有收到任何錯誤,stream()但我仍然收到copyErr=unexpected EOF錯誤all(),看起來最后all.in缺少校驗和數據,但我認為這只是一個意外。


查看完整回答
反對 回復 2022-10-24
?
白豬掌柜的

TA貢獻1893條經驗 獲得超10個贊

通過仔細調試,我能夠看到我錯誤地傳遞了太大的緩沖區切片,這導致不正確的輸入緩沖區被饋送到解壓縮。

此外,重要的是不要使用io.Copy,這會導致緩沖區上的 EOF 停止一切,而是只使用 zlibReader.Read(),這將解壓縮當前在緩沖區中的所有內容。

我已經更新了代碼,所以它現在可以按預期工作。


查看完整回答
反對 回復 2022-10-24
  • 2 回答
  • 0 關注
  • 278 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號