RPC工作流程图
- 1.调用客户端句柄;执行传送参数
- 2.调用本地系统内核发送网络消息
- 3.消息传送到远程主机
- 4.服务器句柄得到消息并取得参数
- 5.执行远程过程
- 6.执行的过程将结果返回服务器句柄
- 7.服务器句柄返回结果,调用远程系统内核
- 8.消息传回本地主机
- 9.客户句柄由内核接收消息
- 10.客户接收句柄返回的数据
Go语言提供对RPC的支持:HTTP、TCP、JSPNRPC
,但是在Go
中RPC
是独一无二的,它采用了GoLang Gob
编码,只能支持Go语言!
- GoLang Gob:是Golang包自带的一个数据结构序列化的编码/解码工具。编码使用Encoder,解码使用Decoder。一种典型的应用场景就是RPC(remote procedure calls)。
HTTP RPC Demo
- 服务端的代码
package main import ( "errors" "fmt" "net/http" "net/rpc" ) type Arith int func rpcDemo() { arith := new(Arith) fmt.Println("arith===", arith) rpc.Register(arith) //HandleHTTP将RPC消息的HTTP处理程序注册到Debug服务器 //DEFAUTUPCPATH和Debug调试路径上的调试处理程序。 //仍然需要调用http.Services(),通常是在GO语句中。 rpc.HandleHTTP() err := http.ListenAndServe(":1234", nil) if err != nil { fmt.Println("err=====", err.Error()) } } type Args struct { A, B int } type Quotient struct { Quo, Rem int } //函数必须是导出的(首字母大写) //必须有两个导出类型的参数, //第一个参数是接收的参数,第二个参数是返回给客户端的参数,第二个参数必须是指针类型的 //函数还要有一个返回值error func (t *Arith) Multiply(args *Args, reply *int) error { *reply = args.A * args.B fmt.Println("这个方法执行了啊---嘿嘿--- Multiply ", reply) 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 fmt.Println("这个方法执行了啊---嘿嘿--- Divide quo==", quo) return nil } func main() { rpcDemo() }
服务端运行:go run server.go
- 客户端的代码
package main import ( "flag" "fmt" "log" "net/rpc" "strconv" ) type ArgsTwo struct { A, B int } type QuotientTwo struct { Quo, Rem int } type Conf struct { serverAddress string i1 string i2 string } var conf = Conf{} func SetConfiguration() { flag.StringVar(&conf.serverAddress, "address", "127.0.0.1:1234", "The address of the rpc") flag.StringVar(&conf.i1, "i1", "100", "100") flag.StringVar(&conf.i2, "i2", "2", "2") } func main() { SetConfiguration() flag.Parse() fmt.Println("severAddress = ", conf.serverAddress) // DelayHTTP在指定的网络地址连接到HTTP RPC服务器 // 在默认HTTP RPC路径上监听。 client, err := rpc.DialHTTP("tcp", conf.serverAddress) if err != nil { log.Fatal("发生错误了 在这里地方 DialHTTP", err) } i1_, _ := strconv.Atoi(conf.i1) i2_, _ := strconv.Atoi(conf.i2) args := ArgsTwo{A: i1_, B: i2_} var reply int //调用调用命名函数,等待它完成,并返回其错误状态。 err = client.Call("Arith.Multiply", args, &reply) if err != nil { log.Fatal("Call Multiply 发生错误了哦 arith error:", err) } fmt.Printf("Arith 乘法: %d*%d=%d ", args.A, args.B, reply) var quot QuotientTwo //调用调用命名函数,等待它完成,并返回其错误状态。 err = client.Call("Arith.Divide", args, ") if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith 除法取整数: %d/%d=%d 余数 %d ", args.A, args.B, quot.Quo, quot.Rem) }
客户端编译:go build client.go
客户端运行: -
[root@wangjq rpc]# ./client severAddress = 127.0.0.1:1234 Arith 乘法: 100*2=200 Arith 除法取整数: 100/2=50 余数 0 [root@wangjq rpc]# [root@wangjq rpc]# ./client --address 127.0.0.1:1234 -i1 200 -i2 5 severAddress = 127.0.0.1:1234 Arith 乘法: 200*5=1000 Arith 除法取整数: 200/5=40 余数 0