RPC简介与实践

  本文是RPC的简介与实践,首先介绍一下RPC的概念与原理,接着介绍一下Go语言对RPC的支持,最后提供一个Go语言原生RPC的简单demo。

 

一、RPC是什么

  RPC,全称:Remote Procedure Call,中文翻译:远程过程调用。

  RPC是一种技术思想,而非规范或协议,它指的是,本地计算机程序通过网络向远程计算机程序请求服务,隐藏底层网络技术,使其看起来就像调用本地函数一样简便,服务提供方与调用方都无需了解底层网络的传输细节。

 

二、RPC是怎么工作的

1. RPC框架的组成

(1)客户端(Client):服务调用者。

(2)服务端(Server):服务提供者。

(3)客户端存根(Client Stub):存放服务端的地址信息,负责将客户端的请求参数打包成网络消息,通过网络远程发送给服务方。

(4)服务端存根(Server Stub):接收调用方发送过来的消息,将消息解包,并调用本地的方法。

(5)底层网络传输:可以是TCP或HTTP。

2. 一次完整的RPC调用流程

简单图示:

详细介绍:

(1)客户端通过本地调用的方式调用服务。

(2)客户端存根接收到调用请求后负责将调用的方法、参数等信息序列化成网络消息体,找到远程服务的地址,将消息通过网络发送给服务方。

(3)服务端存根接收到消息后进行解码(反序列化),根据解码结果调用本地服务。

(4)服务端调用本地方法进行业务逻辑处理,然后将处理结果返回给服务端存根。

(5)服务端存根将调用结果序列化,然后通过网络发送给调用方。

(6)客户端存根收到消息,将消息进行解码(方序列化),得到调用结果,将结果发送给客户端。

(7)客户端最终得到服务调用结果。

 

三、Go语言对RPC的支持

1. Go内置RPC

  Go标准包“net/rpc”中已经提供了对RPC的支持,而且支持三个级别的RPC:TCP、HTTP、JSONRPC。但Go的RPC只支持Go开发的服务器与客户端之间的交互,无法跨语言调用,因为在内部,它们采用了Gob编码。

2. 什么是Gob编码

  Gob是Go语言内置的编解码方式,可以支持变长类型的编解码(意味着通用)而且它的效率比json,xml更高。

3. Go的RPC函数怎么写

  Go RPC函数只有符合下面的条件才能被远程访问,否则会被忽略:

(1)函数必须是导出的(函数名称首字母大写)。

(2)必须有两个导出类型的参数,第一个是接收的参数,第二个是返回给客户端的参数,第二个参数必须是指针类型的。

(3)必须有一个error类型的返回值。

4. 一个简单的demo

  这里提供一个基于TCP的RPC简单demo,逻辑很简单,就是求两个整型数值的乘机与商余,代码如下。

(1)服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* rpc demo tcp server - 求两数的乘积与商余
* author: JetWu
* date: 2020.04.21
 */
package main
 
import (
    "errors"
    "fmt"
    "log"
    "net"
    "net/rpc"
    "time"
)
 
//接收参数
type Args struct {
    A, B int
}
 
//返回参数
type Quotient struct {
    Quo, Rem int
}
 
//RPC服务函数
 
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() {
    //RPC服务注册
    arith := new(Arith)
    rpc.Register(arith)
 
    tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
    if err != nil {
        log.Fatal("net.ResolveTCPAddr err: ", err)
    }
    //监听网络
    listener, err := net.ListenTCP("tcp", tcpAddr)
    if err != nil {
        log.Fatal("net.ListenTCP err: ", err)
    }
    defer listener.Close()
    log.Println("rpc demo tcp server started ...")
 
    for {
        fmt.Printf("accepted at %v\n", time.Now())
        //等待客户端连接
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("listener.Accept err: ", err)
            continue
        }
        fmt.Printf("getted at %v\n", time.Now())
        //为客户端提供服务
        go rpc.ServeConn(conn)
    }
}

 

(2)客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* rpc demo tcp client - 求两数的乘积与商余
* author: JetWu
* date: 2020.04.21
 */
package main
 
import (
    "fmt"
    "log"
    "net/rpc"
)
 
//接收参数
type Args struct {
    A, B int
}
 
//返回参数
type Quotient struct {
    Quo, Rem int
}
 
func main() {
    //连接服务端
    client, err := rpc.Dial("tcp", ":1234")
    if err != nil {
        log.Fatal("rpc.Dial error: ", err)
    }
    log.Println("successfully connected to the rpc demo tcp server ...")
 
    //RPC服务调用
 
    args := Args{17, 8}
    var reply int
    err = client.Call("Arith.Multiply", args, &reply)
    if err != nil {
        log.Fatal("Arith.Multiply error: ", err)
    }
    fmt.Printf("Arith.Multiply: %d * %d = %d\n", args.A, args.B, reply)
 
    var quo Quotient
    err = client.Call("Arith.Divide", args, &quo)
    if err != nil {
        log.Fatal("Arith.Divide error: ", err)
    }
    fmt.Printf("Arith.Divide: %d / %d = %d remainder %d\n", args.A, args.B, quo.Quo, quo.Rem)
}

  

 

posted @   疯一样的狼人  阅读(426)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示