英文:
Behavior change of gzip Reader in golang 1.7.3 (compared to 1.6.3)
问题
我有一个程序,它从网络连接中读取gzip压缩的JSON数据包。发送方在发送gzip数据包后不关闭连接。在go1.6.3
中,这个程序可以正常工作,也就是说,在接收到gzip结束序列后,程序可以解码gzip数据包。但是在go1.7.3
中,程序会阻塞,因为没有收到io.EOF
信号。
下面是一个使用管道模拟网络连接的示例(请注意,写入器保持打开状态以模拟开放的连接):
package main
import (
"fmt"
"encoding/json"
"compress/gzip"
"io"
"runtime"
)
type TestJSON struct {
TestString string `json:"test"`
}
func main() {
fmt.Printf("Version: %s\n", runtime.Version())
pipeReader, pipeWriter := io.Pipe();
go writeTo(pipeWriter);
readFrom(pipeReader);
}
func writeTo(pipeWriter *io.PipeWriter){
// marshall and compress
testJSON := TestJSON{TestString: "test",}
jsonString, err := json.Marshal(testJSON)
if err != nil {
fmt.Printf("Marshalling Error: %s\n", err)
return
}
gzipOut := gzip.NewWriter(pipeWriter)
_, err = gzipOut.Write(jsonString)
if err != nil {
fmt.Printf("Error Writing: %s\n", err)
return
}
gzipOut.Close()
//pipeWriter.Close()
}
func readFrom(pipeReader *io.PipeReader){
// decompress and unmarshall
gzipIn, err := gzip.NewReader(pipeReader)
if err != nil {
fmt.Printf("Error creating reader: %s\n", err)
return
}
defer gzipIn.Close()
jsonDecoder := json.NewDecoder(gzipIn)
msg := new(TestJSON)
err = jsonDecoder.Decode(msg)
if err != nil {
fmt.Printf("Error decoding: %s\n", err)
return
}
fmt.Printf("Received: %v\n", msg)
}
基于这种情况,我有两个问题:
- 哪种行为是正确的?
- 如果
go1.7.3
的行为是正确的,我如何在开放的网络连接上解码传入的gzip数据包?
英文:
I have a program that reads gzip compressed json packets from a network connection. The sender does not close the connection after sending the gzip packet. In go1.6.3
this works perfectly, i.e., the gzip packet is decoded after the gzip end-sequence is received, but in go1.7.3
the reader blocks as there is no io.EOF
.
Here is a sample that simulates the network connection using a pipe (note that the writer stays open to simulate the open connection):
package main
import (
"fmt"
"encoding/json"
"compress/gzip"
"io"
"runtime"
)
type TestJSON struct {
TestString string `json:"test"`
}
func main() {
fmt.Printf("Version: %s\n", runtime.Version())
pipeReader, pipeWriter := io.Pipe();
go writeTo(pipeWriter);
readFrom(pipeReader);
}
func writeTo(pipeWriter *io.PipeWriter){
// marshall and compress
testJSON := TestJSON{TestString: "test",}
jsonString, err := json.Marshal(testJSON)
if err != nil {
fmt.Printf("Marshalling Error: %s\n", err)
return
}
gzipOut := gzip.NewWriter(pipeWriter)
_, err = gzipOut.Write(jsonString)
if err != nil {
fmt.Printf("Error Writing: %s\n", err)
return
}
gzipOut.Close()
//pipeWriter.Close()
}
func readFrom(pipeReader *io.PipeReader){
// decompress and unmarshall
gzipIn, err := gzip.NewReader(pipeReader)
if err != nil {
fmt.Printf("Error creating reader: %s\n", err)
return
}
defer gzipIn.Close()
jsonDecoder := json.NewDecoder(gzipIn)
msg := new(TestJSON)
err = jsonDecoder.Decode(msg)
if err != nil {
fmt.Printf("Error decoding: %s\n", err)
return
}
fmt.Printf("Recived: %v\n", msg)
}
Based on this situation I have 2 questions:
- Which is the correct behavior?
- If
go1.7.3
behaves correctly, how can I decode incoming gzip packets on an open network connection?
答案1
得分: 2
你所看到的是正确的行为。gzip.Reader的旧行为是它能够在没有io.EOF
的情况下返回最后的读取结果,然后在后续调用中返回(0, io.EOF)
。现在它正确地等待io.EOF
,它将阻塞等待下一个gzip头或io.EOF
。
如果你不希望有更多的文件,并且希望gzip尾部指示文件结束,而不管io.EOF
如何,你需要设置Reader.Multistream(false)
。
在添加了这个设置之后,你的示例可以正常工作:
func readFrom(pipeReader *io.PipeReader) {
// 解压缩和反序列化
gzipIn, err := gzip.NewReader(pipeReader)
if err != nil {
fmt.Printf("创建读取器时出错:%s\n", err)
return
}
gzipIn.Multistream(false)
}
https://play.golang.org/p/BdaulxMza0
英文:
What you're seeing is the correct behavior. The old behavior of the gzip.Reader was a side effect of it being able to return a final read without io.EOF
, then (0, io.EOF)
in a subsequent call. Now that it properly waits for io.EOF
, it will block waiting for the next gzip header or io.EOF
.
If you don't expect more files, and you want to have the gzip trailer indicate the end of the file regardless of io.EOF
, you have to set Reader.Multistream(false)
.
Your example works with that addition:
func readFrom(pipeReader *io.PipeReader) {
// decompress and unmarshall
gzipIn, err := gzip.NewReader(pipeReader)
if err != nil {
fmt.Printf("Error creating reader: %s\n", err)
return
}
gzipIn.Multistream(false)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论