- 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)
}
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)
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)
}
}
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)
}