The RPC server will be saved as RPCserver.go, and it will be presented in five parts.
The first part of RPCserver.go is as follows:
package main import ( "fmt" "math" "net" "net/rpc" "os" "sharedRPC" )
The second segment of RPCserver.go contains the following Go code:
type MyInterface struct{} func Power(x, y float64) float64 { return math.Pow(x, y) } func (t *MyInterface) Multiply(arguments *sharedRPC.MyFloats, reply *float64) error { *reply = arguments.A1 * arguments.A2 return nil } func (t *MyInterface) Power(arguments *sharedRPC.MyFloats, reply *float64) error { *reply = Power(arguments.A1, arguments.A2) return nil }
In the preceding Go code, the RPC server implements the desired interface as well as a helper function named Power().
The third segment of RPCserver.go is as follows:
func main() { PORT := ":1234" arguments := os.Args if len(arguments) != 1 { PORT = ":" + arguments[1] }
The fourth part of RPCserver.go contains the following code:
myInterface := new(MyInterface) rpc.Register(myInterface) t, err := net.ResolveTCPAddr("tcp4", PORT) if err != nil { fmt.Println(err) return } l, err := net.ListenTCP("tcp4", t) if err != nil { fmt.Println(err) return }
What makes this program an RPC server is the use of the rpc.Register() function. However, as the RPC server uses TCP, it still needs to make function calls to net.ResolveTCPAddr() and net.ListenTCP().
The rest of the Go code of RPCclient.go is as follows:
for { c, err := l.Accept() if err != nil { continue } fmt.Printf("%s ", c.RemoteAddr()) rpc.ServeConn(c) } }
The RemoteAddr() function returns the IP address and the port number used for communicating with the RPC client. The rpc.ServeConn() function serves the RPC client.
Executing RPCserver.go and waiting for RPCclient.go will create the following output:
$ go run RPCserver.go 127.0.0.1:52289
Executing RPCclient.go will create the following output:
$ go run RPCclient.go localhost:1234 Reply (Multiply): -8.000000 Reply (Power): 0.250000