2016-05-19 7 views
0

Ich kann die Enden eines TCP net.Conn mit einem encoding/gob de/decoder einwickeln und einen Wert damit erfolgreich decodieren/dekodieren, aber wenn ich folge die Decode mit einem Read auf der rohen Verbindung auf dem Read hängt:TCP `net.Conn.Read` hängt nach der Verwendung eines` encoding/gob` Dekoders

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") 
} 

der Ausgang:

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 

Dieses eine deadlock panic im Go Spielplatz verursacht und hängt an meinem lokalen Rechner (0.123.), obwohl der Code zeitweise vollständig ausgeführt wird.

Dies geschieht nicht, wenn ich ein net.PipeConn verwenden oder wenn ich die Decode mit einem Write stattdessen folgen (d tauscht die Reihenfolge der Read/Write nach dem de/dekodieren). Der Code nach dem en/decode funktioniert auch isoliert, wenn ich den en/decode entziehe.

Was verursacht diesen Hang? Dies fühlt sich an wie ein Caching-Problem, aber ich weiß nicht, warum die Write nicht flush oder warum die Read würde nicht die neuesten verfügbaren Daten ziehen, oder warum dieses Problem nur auftritt, wenn gob en/Decodierung beteiligt ist.

Antwort

1

gob wickelt den Leser in einem bufio.Reader, wenn der Leser nicht bereits ein bufio ist, haben Sie 2 Möglichkeiten wirklich:

  1. Ihren Conn in einem bufio.Reader Wickel und das zu gob passieren und verwenden Sie es aus dieser Punkt weiter.
  2. Verwenden Sie Gob für alles und nicht manuell lesen/schreiben.
+0

Ah, ich glaube, ich verstehe, in unteren Begriffen gelesen der Puffer wahrscheinlich das zusätzliche Byte, das ich sendete? Vielen Dank für die Antwort! –