今天和大家聊聊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) 910//準備編碼的資料11type P struct {12 X, Y, Z int13 Name string14}1516//接收解碼結果的結構17type Q struct {18 X, Y *int3219 Name string20}2122func main() {23 //初始化一個資料24 data := P{3, 4, 5, "CloudGeek"}25 //編碼後得到buf位元組切片26 buf := encode(data)27 //用於接收解碼資料28 var q *Q29 //解碼操作30 q = decode(buf)31 //"CloudGeek": {3,4}32 fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)3334}3536func encode(data interface{}) *bytes.Buffer {37 //Buffer類型實現了io.Writer介面38 var buf bytes.Buffer39 //得到編碼器40 enc := gob.NewEncoder(&buf)41 //調用編碼器的Encode方法來編碼資料data42 enc.Encode(data)43 //編碼後的結果放在buf中44 return &buf45}4647func decode(data interface{}) *Q {48 d := data.(io.Reader)49 //擷取一個解碼器,參數需要實現io.Reader介面50 dec := gob.NewDecoder(d)51 var q Q52 //調用解碼器的Decode方法將資料解碼,用Q類型的q來接收53 dec.Decode(&q)54 return &q55}
例2:資料結構到檔案的序列化和還原序列化
1package main 2 3import ( 4 "encoding/gob" 5 "os" 6 "fmt" 7) 8 9//實驗用的資料類型10type Address struct {11 City string12 Country string13}1415//序列化後資料存放的路徑16var filePath string1718func main() {19 filePath = "./address.gob"20 encode()21 pa := decode()22 fmt.Println(*pa) //{Chengdu China}23}2425//將資料序號後寫到檔案中26func encode() {27 pa := &Address{"Chengdu", "China"}28 //開啟檔案,不存在的時候建立29 file, _ := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0666)30 defer file.Close()3132 //encode後寫到這個檔案中33 enc := gob.NewEncoder(file)34 enc.Encode(pa)35}3637//從檔案中讀取資料並還原序列化38func decode() *Address {39 file, _ := os.Open(filePath)40 defer file.Close()4142 var pa Address43 //decode操作44 dec := gob.NewDecoder(file)45 dec.Decode(&pa)46 return &pa47}
上面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 int11}1213//定義一個算術類型,其實就是int14type Arith int1516//實現乘法的方法綁定到Arith類型,先不管為什麼是這樣的形式17func (t *Arith) Multiply(args *Args, reply *int) error {18 *reply = args.A * args.B19 return nil20}2122func main() {23 //得到一個Arith類型的指標執行個體24 arith := new(Arith)25 //註冊到rpc服務26 rpc.Register(arith)27 //掛到http服務上28 rpc.HandleHTTP()29 //開始監聽30 l, _ := net.Listen("tcp", ":1234")31 http.Serve(l, nil)32}
rpc用戶端
1package main 2 3import ( 4 "net/rpc" 5 "fmt" 6) 7 8type Args struct { 9 A, B int10}1112func main() {13 //串連伺服器端,建立一個client14 client, _ := rpc.DialHTTP("tcp", "127.0.0.1:1234")15 args := &Args{7, 8}16 var reply int17 //通過Call方法調用Arith類型的Multiply方法,注意形參18 client.Call("Arith.Multiply", args, &reply)19 //得到調用結果,輸出Arith: 7*8=5620 fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)21}
上面2段程式很簡短,可能你現在還不能理解其中的細節,但也請耐心看完,這個時候你應該能夠心裡有個rpc調用的概念了,用戶端直接調用了伺服器端的一個函數傳遞過去參數列表和接收傳回值的對象,獲得調用結果。
三、rpc的一些細節
下面我們再來看一些rpc相關的細節
首先能夠被rpc調用的方法應該看起來像這樣:
func (t *T) MethodName(argType T1, replyType *T2) error
大概解釋一下:
- 必須有兩個匯出類型的參數,第一個參數用來接收參數,第二個參數是返回給用戶端的結果參數,第二個參數必須是指標類型的
看到這裡你應該對於rpc的作用有了一定的認識,go中rpc包的用法簡單來看就是準備一個類型,綁定一堆符合規範的方法,然後註冊給rpc服務,監聽用戶端串連,用戶端通過rpc包提供的Call方法可以調用到server註冊好的方法。更多細節可以看一下官方文檔:https://golang.org/pkg/net/rpc/
124 次點擊