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 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了