什么是RPC?
RPC是Remote Procedure Call的缩写,从字面意思理解就是远程过程调用,具体可以见维基百科的解释,如果你英文足够好可以看这里wikipedia,我的理解可以简单的用一句话来描述:RPC就是一个本地程序可以通过网络调用远程的一个子程序。
Go RPC
Go的RPC中如果客户端是Go语言编写的则将用Go特有的Gob序列化,同时可以选择rpc/jsonrpc包来用json格式序列化以便和其他的RPC System交互。
Go中的RPC有以下几个限制:
1.Remote Procedure必须是公共的,对于Go的话函数首字母必须大写。
2.Remote Procedure必须又且仅有两个参数,第一个参数是一个指向从客户端接受的数据指针,第二个参数是一个指向返回给客户端数据的指针。
3.返回值是一个error
例如,如下函数是正确的:
func F(&t1,&2) error
在rpc的Server端,我们需要通过Register方法为一个接口完成“注册”,“注册”完成之后客户端就可以通过这个接口的方法调用远程过程(Remote Procedure),例如:rpc.Register(obj)
一个例子:
ArithServer:
package main
import (
"fmt"
"net/rpc"
"errors"
"net/http"
)
type Args struct {
A,B int
}
type Quotient struct {
Quo,Rem int
}
type Arith int
// 需要远程调用的方法
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
// 需要远程调用的方法
func (t *Arith) Divide(args *Args,quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
arith := new(Arith)
// 注册
rpc.Register(arith)
rpc.HandleHTTP()
err := http.ListenAndServe(":1234",nil)
if err != nil {
fmt.Println(err.Error())
}
}
ArithClient:
package main
import (
"net/rpc"
"fmt"
"log"
"os"
)
type Args struct {
A,B int
}
type Quotient struct {
Quo,Rem int
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: ",os.Args[0],"server")
os.Exit(1)
}
serverAddress := os.Args[1]
client,err := rpc.DialHTTP("tcp", serverAddress+":1234")
if err != nil {
log.Fatal("dialing:",err)
}
// Synchronous call
args := Args{17,8}
var reply int
//远程调用,args是传给远程函数的参数,reply用来接收函数的结果
err = client.Call("Arith.Multiply",args,&reply)
if err != nil {
log.Fatal("arith error:",err)
}
fmt.Printf("Arith: %d*%d=%d\n",args.A,args.B,reply)
var quot Quotient
//远程调用,args是传给远程函数的参数,reply用来接收函数的结果
err = client.Call("Arith.Divide",args,")
if err != nil {
log.Fatal("arith error:",err)
}
fmt.Printf("Arith: %d/%d=%d remainder %d\n",args.A,args.B,quot.Quo,quot.Rem)
}
开启服务端后再运行客户端:
go run ArithClient localhost
结果:
Arith: 17*8=136
Arith: 17/8=2 remainder 1