Go从入门到精通—示例:模拟远程过程调用(RPC)

示例:模拟远程过程调用(RPC)

  服务器开发中会使用 RPC(Remote Procedure Call,远程过程调用)简化进程间通信的过程。RPC 能有效低封装通信过程,让远程的数据收发通信过程看起来就像本地的函数调用一样。

  本例中,使用通道替代 Socket 实现 RPC 的过程。客户端与服务器运行在同一个进程,服务器和客户端在两个 goroutine 中运行。

1、客户端请求和接收封装

  下面的代码封装了向服务器请求数据,等待服务器返回数据,如果请求方超时,该函数还会处理超时逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//模拟 RPC 客户端的请求和接收消息封装
func RPCClient(ch chan string, req string)(string ,error){
     
    //模拟 socket 向服务器发送一个字符串信息。服务器接收后,结束阻塞执行下一行。
    ch <- req
     
    //等待服务器返回
    select {                                        //使用 select 做多路复用
    case ack := <- ch:                               //接收到服务器返回数据
        return ack,nil
    //使用了time包提供的函数After(),从字面意思看就是多少时间之后,其参数是time包的一个常量,time.Second 表示1秒。
    //time.After()返回一个通道,这个通道在指定时间后,通过通道返回当前时间。
    case <-time.After(time.Second):                 
        return "",errors.New("Time out")        //超时时,返回超时错误
         
    }
}

 2、服务器接收和反馈数据

  服务器接收到客户端的任意数据后,先打印再通过通道返回给客户端一个固定字符串,表示服务器已经收到请求。

1
2
3
4
5
6
7
8
9
10
11
12
//模拟 RPC 服务器端接受客户端请求和回应
func RPCServer(ch chan string) (string, error) {
    for {
        //接收客户端请求
        data := <-ch
 
        //打印接收到的数据
        fmt.Println("Server received:", data)
 
        //向客户端反馈已收到
        ch <- "roger"
    }

3、完整代码+模拟超时

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
package main
 
import (
    "errors"
    "fmt"
    "time"
)
 
//模拟 RPC 客户端的请求和接收消息封装
func RPCClient(ch chan string, req string) (string, error) {
 
    //模拟 socket 向服务器发送一个字符串信息。服务器接收后,结束阻塞执行下一行。
    ch <- req
 
    //等待服务器返回
    select { //使用 select 做多路复用
    case ack := <-ch: //接收到服务器返回数据
        return ack, nil
    //使用了time包提供的函数After(),从字面意思看就是多少时间之后,其参数是time包的一个常量,time.Second 表示1秒。
    //time.After()返回一个通道,这个通道在指定时间后,通过通道返回当前时间。
    case <-time.After(time.Second):
        return "", errors.New("time out") //超时时,返回超时错误
 
    }
}
 
//模拟 RPC 服务器端接受客户端请求和回应
func RPCServer(ch chan string) {
    for {
        //接收客户端请求
        data := <-ch
 
        //打印接收到的数据
        fmt.Println("Server received:", data)
 
        //通过睡眠函数让程序执行阻塞 2秒 的任务
        time.Sleep(time.Second * 2)
 
        //向客户端反馈已收到
        ch <- "roger"
    }
}
 
func main() {
    //创建一个无缓存字符串通道
    ch := make(chan string)
 
    go RPCServer(ch)
 
    recv, err := RPCClient(ch, "hi")
    if err != nil {
        //发生错误
        fmt.Println(err)
    } else {
        //正常接收到数据
        fmt.Println("client received", recv)
    }
}

  代码执行结果:

1
2
3
4
5
6
7
8
Starting: D:\go-testfiles\bin\dlv.exe dap --check-go-version=false --listen=127.0.0.1:50443 from d:\go-testfiles
DAP server listening at: 127.0.0.1:50443
Type 'dlv help' for list of commands.
Server received: hi
time out
Process 7812 has exited with status 0
Detaching
dlv dap (9404) exited with code: 0
posted @   左扬  阅读(149)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
levels of contents
点击右上角即可分享
微信分享提示