今天和大家聊聊golang中怎麼使用rpc,rpc數據傳輸會涉及到gob編碼,所以先講講gob,別擔心,就算你完全沒有接觸過gob與rpc,只要知道rpc的中文是遠程過程調用,剩下的我都能給你講明白(帶你入門不包你精通)! 一、數據結構編碼之gob gob全稱為:Go binary Golang自帶 ...
今天和大家聊聊golang中怎麼使用rpc,rpc數據傳輸會涉及到gob編碼,所以先講講gob,別擔心,就算你完全沒有接觸過gob與rpc,只要知道rpc的中文是遠程過程調用,剩下的我都能給你講明白(帶你入門不包你精通)!
一、數據結構編碼之gob
gob全稱為:Go binary
Golang自帶的一個數據結構序列化編碼/解碼工具,也就是說gob可以講go中的一個數據結構序列化成某種東西,還能反序列化!序列化成啥我們後面來看,不管是變成一個字元串,變成二進位流,變成啥先不管,反正作用就是序列化。
Gob使用時我們需要關註Encoder和Decoder對象,顧名思義,一個是編碼的時候用的,一個是解碼的時候用的,我們看一下怎麼獲取這兩個對象先:
所以很明確,需要調用這兩個函數來獲取Encoder和Decoder對象。註意這裡的參數是io.Writer和io.Reader介面類型,我們在上一講介紹過這兩個介面,所以這裡需要的參數分別是實現了io.Writer和io.Reader介面類型的對象即可。
Encoder和Decoder分別有一個主要的方法是:
看到這裡我們已經可以得到如下結論:
Gob 使用 io.Writer 介面,通過 NewEncoder() 函數創建 Encoder 對象通過調用 Encode()方法實現編碼操作;使用 io.Reader 介面,通過 NewDecoder() 函數創建 Decoder 對象並調用 Decode()方法完成解碼操作!
接下來我們試著用一下這個Encoder和Decoder,就輕輕鬆松入門gob了,來看第一個例子
例1:數據結構與bytes.Buffer之間的轉換(編碼成位元組切片)
1package main
2
3import (
4 "bytes"
5 "fmt"
6 "encoding/gob"
7 "io"
8)
9
10//準備編碼的數據
11type P struct {
12 X, Y, Z int
13 Name string
14}
15
16//接收解碼結果的結構
17type Q struct {
18 X, Y *int32
19 Name string
20}
21
22func main() {
23 //初始化一個數據
24 data := P{3, 4, 5, "CloudGeek"}
25 //編碼後得到buf位元組切片
26 buf := encode(data)
27 //用於接收解碼數據
28 var q *Q
29 //解碼操作
30 q = decode(buf)
31 //"CloudGeek": {3,4}
32 fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
33
34}
35
36func encode(data interface{}) *bytes.Buffer {
37 //Buffer類型實現了io.Writer介面
38 var buf bytes.Buffer
39 //得到編碼器
40 enc := gob.NewEncoder(&buf)
41 //調用編碼器的Encode方法來編碼數據data
42 enc.Encode(data)
43 //編碼後的結果放在buf中
44 return &buf
45}
46
47func decode(data interface{}) *Q {
48 d := data.(io.Reader)
49 //獲取一個解碼器,參數需要實現io.Reader介面
50 dec := gob.NewDecoder(d)
51 var q Q
52 //調用解碼器的Decode方法將數據解碼,用Q類型的q來接收
53 dec.Decode(&q)
54 return &q
55}
例2:數據結構到文件的序列化和反序列化
1package main
2
3import (
4 "encoding/gob"
5 "os"
6 "fmt"
7)
8
9//試驗用的數據類型
10type Address struct {
11 City string
12 Country string
13}
14
15//序列化後數據存放的路徑
16var filePath string
17
18func main() {
19 filePath = "./address.gob"
20 encode()
21 pa := decode()
22 fmt.Println(*pa) //{Chengdu China}
23}
24
25//將數據序列號後寫到文件中
26func encode() {
27 pa := &Address{"Chengdu", "China"}
28 //打開文件,不存在的時候新建
29 file, _ := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0666)
30 defer file.Close()
31
32 //encode後寫到這個文件中
33 enc := gob.NewEncoder(file)
34 enc.Encode(pa)
35}
36
37//從文件中讀取數據並反序列化
38func decode() *Address {
39 file, _ := os.Open(filePath)
40 defer file.Close()
41
42 var pa Address
43 //decode操作
44 dec := gob.NewDecoder(file)
45 dec.Decode(&pa)
46 return &pa
47}
上面2個例子都不難,我去掉了錯誤處理之類的代碼,儘量註釋了每塊代碼,耐心看完這2個例子應該就能體會gob的encode和decode精髓了。
理解gob是什麼的基礎上,如果你需要使用gob開發,建議詳細看一下官方文檔,瞭解一下更多的細節:https://golang.org/pkg/encoding/gob/
二、golang中的rpc入門
如果你之前沒有做過基於rpc通信的開發工作,直接去網上查rpc相關的知識點的時候很可能會一臉蒙圈,rest api咋就那麼好理解,一個http請求過去就行了,rpc咋個回事,看不懂呀。。。
所以我不會和多數教程一樣為了追求詳細或者展示自己技術多牛而去寫很長的例子,扯一堆專業的概念,我們先最快的方式體驗一下rpc調用的感覺!
rpc服務端
1package main
2
3import (
4 "net"
5 "net/rpc"
6 "net/http"
7)
8
9type Args struct {
10 A, B int
11}
12
13//定義一個算術類型,其實就是int
14type Arith int
15
16//實現乘法的方法綁定到Arith類型,先不管為什麼是這樣的形式
17func (t *Arith) Multiply(args *Args, reply *int) error {
18 *reply = args.A * args.B
19 return nil
20}
21
22func main() {
23 //得到一個Arith類型的指針實例
24 arith := new(Arith)
25 //註冊到rpc服務
26 rpc.Register(arith)
27 //掛到http服務上
28 &nb