Go代码演示RPC协议 | 青训营笔记

123 阅读2分钟

据上课所知,RPC(Remote Procedure Call)远程过程调用,可以让调用者像本地调用一样调用远端服务器的方法,是分布式系统下常见的一种通信方式。本篇笔记是我对 RPC 协议实现的思考,开发环境为 go1.20。

PRC 三个问题:①函数映射 ②数据转换字节流 ③网络传输。解决这三个问题就能实现 RPC 协议。

下面我们将调用者记为 Client,将远端服务器记为 Server,令要调用的函数为 Add(a,b int)实现两数加减,用 JSON协议 和HTTP协议 进行网络传输。

  • 即 Client 向 Server 发起 HTTP 请求,url中包含 add 方法和参数,解决 RPC 第一个问题 ①函数调用;
  • 使用 JSON协议 解决 RPC 第二个问题 ②数据转换字节流;
  • HTTP 则解决 RPC ③网络传输问题。

下面是 Server 端实现代码。在远端服务器 Server 上设置一个 HandleFunc 接收 HTTP 的 Get 请求,请求包含 Add 方法和参数:

func main() {  
    //http://127.0.0.1:8000/add?a=1&b=2  RPC调用的URL
    //返回的格式化: json{"data":3}  
  
    http.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {  
    
        _ = r.ParseForm() // 解析参数, 忽略错误变量  
        //fmt.Println("path:", r.URL.Path)  
        
        a, _ := strconv.Atoi(r.Form["a"][0])  // 提取URL中的第一个变量a,并转为int类型
        b, _ := strconv.Atoi(r.Form["b"][0])  // 提取URL中的第一个变量b,并转为int类型  
        
        w.Header().Set("Content-Type", "application/json")  // 写入该请求头,表示传输的是JSON数据
    
        // 将JSON数据
        jData, _ := json.Marshal(map[string]int{  
            "data": a + b,  
        })  
        _, _ = w.Write(jData)  // 写入数据
    })  
    
    _ = http.ListenAndServe(":8000", nil)  // 监听 Client端的远程调用请求
} 

下面是 Client 端实现代码。在客户端 Client 上创建一个 Add方法,并在 main 中本地调用。

//rpc 远程调用,如何做到像本地调用  

// 接收 JSON 数据的结构体
type ResponseData struct {  
    Data int `json:"data"`  
}  

// 模拟本地调用,实际忽略底层的网络传输
func Add(a, b int) int {  
    //传输协议:HTTP  
    // 向远端服务器 Server 发起 add 方法请求
    req := HttpRequest.NewRequest()  // 用了这个库"github.com/kirinlabs/HttpRequest",可以自行用http包实现
    res, _ := req.Get(fmt.Sprintf("http://127.0.0.1:8000/%s?a=%d&b=%d", "add", a, b))  
    body, _ := res.Body()  // 得到数据是JSON格式
    //fmt.Println(string(body))  
    
    resData := ResponseData{}  
    _ = json.Unmarshal(body, &resData)  // 将JSON数据解码为结构体
    return resData.Data  
}  
  
func main() {  
        result := Add(1, 2)  // 1 + 2,模拟本地调用,实际忽略底层的网络传输
    fmt.Println("输出结果:", result) // 输出结果:3
}

以上。