Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/rpc: strange behavior in rpc using default codec #8997

Open
gopherbot opened this issue Oct 25, 2014 · 5 comments
Open

net/rpc: strange behavior in rpc using default codec #8997

gopherbot opened this issue Oct 25, 2014 · 5 comments
Milestone

Comments

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 25, 2014

by HongF.Yue:

go version:go version go1.3.3 linux/amd64

I discovered a strange behavior related to 0 value in reply structure. The codes below
will produce this problem.
---------------------------------------------------
```go
//rpc server
package main

import (
    "fmt"
    "net"
    "net/rpc"
    "os"
)

type Args struct {
    A int
}

type Rsp struct {
    A int
}

type Echoer int

var isFirst = true

func (t *Echoer) Echo(args *Args, reply *Rsp) error {
    if isFirst {
        reply.A = args.A
        isFirst = false
    } else {
        reply.A = 0
    }
    fmt.Println("reply-----", reply.A)
    return nil
}

func main() {
    echoer := new(Echoer)
    rpc.Register(echoer)

    tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
    checkError(err)

    listener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)

    for {
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        rpc.ServeConn(conn)
    }

}

func checkError(err error) {
    if err != nil {
        fmt.Println("Fatal error ", err.Error())
        os.Exit(1)
    }
}
```
---------------------------------------------------
```go
//rpc client
package main

import (
    "fmt"
    "log"
    "net/rpc"
    "os"
    "time"
)

type Args struct {
    A int
}

type Rsp struct {
    A int
}

func main() {
    if len(os.Args) != 2 {
        fmt.Println("Usage: ", os.Args[0], "server:port")
        os.Exit(1)
    }
    service := os.Args[1]
    client, err := rpc.Dial("tcp", service)
    if err != nil {
        log.Fatal("dialing:", err)
    }
    args := Args{3}
    var rsp Rsp
    for {
        err = client.Call("Echoer.Echo", args, &rsp)
        if err != nil {
            log.Fatal("arith error:", err)
        }
        fmt.Printf("Echoer: A=%d\n", rsp.A)
        time.Sleep(time.Second * 2)
    }
}
```
------------------------------------------
The output of server:
reply----- 3
reply----- 0
reply----- 0
reply----- 0

The output of client:
Echoer: A=3
Echoer: A=3         //why is not A=0
Echoer: A=3
Echoer: A=3

The client should print A=3 on the first time and others would be A=0. More test code
showed that this behavior related to zero values in the RPC reply. When server reply
zero values, client print last reply which is not zero. 

When I change codec to msgpack, this problem doesn't happen. I also found that in rpc
client code, when I move ```var rsp Rsp``` to inner of for loop, everything goes well. 

Is this a bug? or I misunderstand somewhere of golang?
@davecheney

This comment has been minimized.

Copy link
Contributor

@davecheney davecheney commented Oct 25, 2014

Comment 1:

Drive by comment, have you run your server program under the go race detector?
@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Oct 25, 2014

Comment 2:

Labels changed: added repo-main, release-none.

@gopherbot

This comment has been minimized.

Copy link
Author

@gopherbot gopherbot commented Oct 26, 2014

Comment 3 by HongF.Yue:

I rebuild and run server code in -race flag, and edit rpc server code as below:
----------------------------------------
//rpc server
package main
import (
    "fmt"
    "net"
    "net/rpc"
    "os"
)
type Args struct {
    A int
}
type Rsp struct {
    A int
}
type Echoer int
var isFirst = true
func (t *Echoer) Echo(args *Args, reply *Rsp) error {
    if isFirst {
        reply.A = args.A
        isFirst = false
    } else {
        reply.A = 0
    }
    fmt.Println("reply-----", reply.A)
    return nil
}
func main() {
    echoer := new(Echoer)
    rpc.Register(echoer)
    tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
    checkError(err)
    listener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)
    conn, err := listener.Accept()
    checkError(err)
    rpc.ServeConn(conn)
}
func checkError(err error) {
    if err != nil {
        fmt.Println("Fatal error ", err.Error())
        os.Exit(1)
    }
}
----------------------------------
The output of both client and server have nothing different from original. And sending
Ctrl-C to client, server exit with no warning or error. 
The Processor of this server is only one, I don't think this problem is related to
concurrent or race condition. Maybe some strange behavior of gob codec (zero value) is
the answer.
@gopherbot gopherbot added new labels Oct 26, 2014
@bradfitz bradfitz removed the new label Dec 18, 2014
@boydc2014

This comment has been minimized.

Copy link

@boydc2014 boydc2014 commented Mar 5, 2015

Running to the same issue here. When reply value is 0(for int type), it seems that the decoder just overlook this field.

A simpler way to reproduce is,
let "rsp := {A:3}" and let the function make "reply.A = 0", you can see what happens.

@rsc rsc added this to the Unplanned milestone Apr 10, 2015
@rsc rsc removed release-none labels Apr 10, 2015
@mljli

This comment has been minimized.

Copy link

@mljli mljli commented Oct 10, 2016

I also found that in rpc client code, when I move var rsp Rsp to inner of for loop, everything goes well.

Still have the same issue with Go 1.7.1. When will this be fixed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
7 participants
You can’t perform that action at this time.