douhuangzhi0707 2016-05-19 17:49
浏览 16
已采纳

使用`encoding / gob`解码器后,TCP`net.Conn.Read`挂起

I can wrap ends of a TCP net.Conn with an encoding/gob en/decoder and en/decode a value through it successfully, but if I follow the Decode with a Read on the raw connection it hangs on the Read:

package main

import (
    "encoding/gob"
    "net"
    "log"
    "sync"
)

func main() {
    var wg sync.WaitGroup

    addr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9000}
    ready := make(chan struct{})

    wg.Add(1)
    go func() {
        defer wg.Done()

        ln, err := net.ListenTCP("tcp4", addr)
        if err != nil {
            log.Fatal("ln: ", err)
        }
        defer ln.Close()

        close(ready)

        conn, err := ln.Accept()
        if err != nil {
            log.Fatal("conn: ", err)
        }
        defer conn.Close()

        var out string
        if err := gob.NewDecoder(conn).Decode(&out); err != nil {
            log.Fatal("error decoding: ", err)
        }
        if "hello" != out {
            log.Fatalf("1 expected '%s', got '%s'", "hello", out)
        }

        b := make([]byte, 1)
        log.Println("ready to read 1")
        if _, err := conn.Read(b); err != nil {
            log.Fatal("error reading: ", err)
        }
        log.Println("read 1")
        if b[0] != 1 {
            log.Fatalf("2 expected '%d', got '%d'", 1, b[0])
        }

        if _, err := conn.Write([]byte{1}); err != nil {
            log.Fatal("err writing2: ", err)
        }
        log.Println("done 1")
    }()

    wg.Add(1)
    go func() {
        defer wg.Done()

        <-ready

        conn, err := net.DialTCP("tcp4", nil, addr)
        if err != nil {
            log.Fatal("conn2: ", err)
        }
        defer conn.Close()

        if err := gob.NewEncoder(conn).Encode("hello"); err != nil {
            log.Fatal("error encoding: ", err)
        }

        if _, err := conn.Write([]byte{1}); err != nil {
            log.Fatal("write error: ", err)
        }

        b := make([]byte, 1)
        log.Println("ready to read 2")
        if _, err := conn.Read(b); err != nil {
            log.Fatal("error reading2: ", err)
        }
        log.Println("read 2")
        if b[0] != 1 {
            log.Fatalf("3 expected '%d', got '%d'", 1, b[0])
        }
        log.Println("done 2")
    }()

    log.Println("waiting")
    wg.Wait()
    log.Println("waited")
}

The output:

2009/11/10 23:00:00 waiting
2009/11/10 23:00:00 ready to read 2
2009/11/10 23:00:00 ready to read 1

This causes a deadlock panic in the Go Playground and hangs on my local machine (go version go1.6.2 darwin/amd64), though intermittently the code will execute to completion locally.

This doesn't happen if I use a net.PipeConn or if I follow the Decode with a Write instead (i.e. swap the order of the Read/Write following the en/decode). The code following the en/decode also works in isolation when I remove the en/decode code.

What is causing this hang? This feels like a caching issue but I don't know why the Write wouldn't flush or why the Read wouldn't pull the latest available data, or why this issue only appears when gob en/decoding is involved.

  • 写回答

1条回答 默认 最新

  • douyan1896 2016-05-19 18:12
    关注

    gob wraps the reader in a bufio.Reader if the reader isn't already a bufio, you really have 2 options:

    1. Wrap your conn in a bufio.Reader and pass that to gob and use it from that point on.
    2. Use gob for everything and don't manually read/write.
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥200 uniapp长期运行卡死问题解决
  • ¥15 latex怎么处理论文引理引用参考文献
  • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?