I'm trying to to send an encoded blob to a list of local peers(a client code listening at multiple ports on a local machine), at the peers when i decode the blob for some peers it works but for some it doesn't and displays an error(gob: unknown type id or corrupted data), how can i solve this ?
//My blob struct
type packet struct {
Nodes []a1.Node
Ledger *a1.Block
ActionType string
}
//Encoding Part
for i:=1; i<len(ConnectedNodes);i++{
var blob packet
blob.Ledger = Ledger
blob.ActionType = "AddBlock"
blob.Nodes = []a1.Node{}
conn, err := net.Dial("tcp", "localhost"+":"+ConnectedNodes[i].Port)
if err != nil {
// handle error
fmt.Println("Error At Client In Making A Connection (sending New Block to client "+ ConnectedNodes[i].Name +")")
}
//sending request type to client
_, _ = conn.Write([]byte("newblock add "))
//sending data to the client node
//gob.Register(blob)
encoder := gob.NewEncoder(conn)
error := encoder.Encode(blob)
if error != nil {
log.Fatal(error)
}
}
//Decoding Part running on another peer
//adds new block to the Ledger
//Recieving incoming data
recvdSlice := make([]byte, 256)
conn.Read(recvdSlice)
RecievedData := string(recvdSlice)
finalData := strings.Split(RecievedData, " ")
if finalData[0] == "newblock"{
var blob packet
decoder := gob.NewDecoder(conn)
err := decoder.Decode(&blob)
if err != nil {
fmt.Println("error at decoding New Block on client!")
fmt.Println(err)
}
fmt.Println(Ledger.Hash)
fmt.Println(blob.Ledger.Hash)
if(bytes.Compare(Ledger.Hash, blob.Ledger.Hash)) == 0 {
fmt.Println("Ledger is already updated !")
}else{
fmt.Println("New Block Added !")
Ledger = blob.Ledger
}
a1.ListBlocks(Ledger)
//SendingNewBlockToConnectedNodes()
}
The sender writes 13 bytes before encoding gob ("newblock add "
).
If the receiver does not read these 13 bytes before decoding the gob, then the decoder will be out of sync with the data stream and report an error.
The connection Read method returns when data is available, the slice is filled or there is an error reading the connection. Ignoring errors, the call to Read on the connection will read between 1 and len(recvdSlice) bytes from the connection. There's no guarantee that 13 bytes of data is read, but it happens frequently in practice because of timing.
Fix by reading just the prefix before decoding the gob. One way is to delimit the prefix with a newline.
Change the sender code to:
_, _ = conn.Write([]byte("newblock add \n"))
Change the receiver code to:
br := bufio.NewReader(conn)
receivedData, err := br.ReadString('\n')
if err != nil {
// handle error
}
finalData := strings.Split(receivedData, " ")
if finalData[0] == "newblock"{
var blob packet
decoder := gob.NewDecoder(br) // <-- decode from the buffered reader
err := decoder.Decode(&blob)
Another fix is to use the gob codec for the prefix. Change the sender to:
encoder := gob.NewEncoder(conn)
if err := encoder.Encode("newblock add "); err != nil {
// handle error
}
if err := encoder.Encode(blob); err != nil {
// handle error
}
Change the receiver to:
decoder := gob.NewDecoder(conn)
var receivedData string
if err := decoder.Decode(&receivedData); err != nil {
// handle error
}
finalData := strings.Split(receivedData, " ")
if finalData[0] == "newblock"{
var blob packet
err := decoder.Decode(&blob)