Golang中的RPC(转载)
-
RPC 简介
- 远程过程调用(Remote Procedure Call,缩写为 RPC)
- 可以将一些比较通用的场景抽象成微服务,然后供其他系统远程调用
- RPC 可以基于HTTP协议 也可以基于TCP协议,基于HTTP协议的RPC像是我们访问网页一样(GET/POST/PUT/DELETE/UPDATE),大部分的RPC都是基于TPC协议的(因为基于传输层,效率稍高一些)
- 基于TCP 的 RPC 工作过程
- 客户端对请求的对象序列化
- 客户端连接服务端,并将序列化的对象通过socket 传输给服务端,并等待接收服务端的响应
- 服务端收到请求对象后将其反序列化还原客户端的对象
- 服务端从请求对象中获取到请求的参数,然后执行对应的方法,得到返回结果
- 服务端将其结果序列化并传给客户端,客户端得到响应结果对象后将其反序列化,得到响应结果
-
Golang中的RPC 注:例子参考 golang实现RPC的几种方式
-
net/rpc库
注:没办法在其他语言中调用上面例子实现的RPC方法
-
服务端 rpc_server.go
package main import ( "errors" "fmt" "log" "net" "net/http" "net/rpc" "os" ) // 算数运算结构体 type Arith struct { } type AirthRequest struct { A int B int } // 算数运算请求结构体 type AirthResponse struct { Pro int // 成绩 Quo int // 商 Rem int // 余数 } // 乘法运算方法 func (this *Arith) Multiply(req AirthRequest, res *AirthResponse) error { res.Pro = req.A * req.B return nil } // 除法运算 func (this *Arith) Divide(req AirthRequest, res *AirthResponse) error { if req.B == 0 { return errors.New("divide by zero") } res.Quo = req.A / req.B res.Rem = req.A % req.B return nil } func main() { rpc.Register(new(Arith)) // 注册rpc服务 rpc.HandleHTTP() //采用http协议作为rpc载体 lis, err := net.Listen("tcp", "127.0.0.1:8905") if err != nil { log.Fatalln("fatal error:", err) } fmt.Println(os.Stdout, "%s", "start connect\n") http.Serve(lis, nil) }
-
客户端 rpc_client.go
package main import ( "fmt" "log" "net/rpc" ) // 运算请求结构体 type AirthRequest struct { A int B int } // 运算响应结构体 type AirthResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数 } func main() { conn, err := rpc.DialHTTP("tcp", "127.0.0.1:8905") if err != nil { log.Fatalln("dialing error:", err) } req := AirthRequest{10, 2} var res AirthResponse err = conn.Call("Arith.Multiply", req, &res) if err != nil { log.Fatalln("arith error:", err) } fmt.Println("%d * %d = %d\n", req.A, req.B, res.Pro) err = conn.Call("Arith.Divide", req, &res) if err != nil { log.Fatal("arith error:", err) } fmt.Printf("%d / %d, quo is %d, rem is %d\n", req.A, req.B, res.Quo, res.Rem) }
-
-
net/rpc/jsonrpc库
注:支持跨语言调用
-
jsonrpc_server.go
package main import ( "errors" "fmt" "log" "net" "net/rpc" "net/rpc/jsonrpc" "os" ) // 算数运算结构体 type Arith struct { } // 算数运算请求结构体 type ArithRequest struct { A int B int } // 算数运算响应结构体 type ArithResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数 } // 乘法运算方法 func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error { res.Pro = req.A * req.B return nil } // 除法运算方法 func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error { if req.B == 0 { return errors.New("divide by zero") } res.Quo = req.A / req.B res.Rem = req.A % req.B return nil } func main() { rpc.Register(new(Arith)) // 注册rpc服务 lis, err := net.Listen("tcp", "127.0.0.1:8096") if err != nil { log.Fatalln("fatal error: ", err) } fmt.Fprintf(os.Stdout, "%s", "start connection") for { conn, err := lis.Accept() // 接收客户端连接请求 if err != nil { continue } go func(conn net.Conn) { // 并发处理客户端请求 fmt.Fprintf(os.Stdout, "%s", "new client in coming\n") jsonrpc.ServeConn(conn) }(conn) } }
-
jsonrpc_client.go
package main import ( "fmt" "log" "net/rpc/jsonrpc" ) // 算数运算请求结构体 type ArithRequest struct { A int B int } // 算数运算响应结构体 type ArithResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数 } func main() { conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8096") if err != nil { log.Fatalln("dailing error: ", err) } req := ArithRequest{9, 2} var res ArithResponse err = conn.Call("Arith.Multiply", req, &res) // 乘法运算 if err != nil { log.Fatalln("arith error: ", err) } fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro) err = conn.Call("Arith.Divide", req, &res) if err != nil { log.Fatalln("arith error: ", err) } fmt.Printf("%d / %d, quo is %d, rem is %d\n", req.A, req.B, res.Quo, res.Rem) }
-
-