中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go實現簡易RPC框架的方法步驟

發布時間:2020-09-25 20:59:18 來源:腳本之家 閱讀:157 作者:Jiahonzheng 欄目:編程語言

本文旨在講述 RPC 框架設計中的幾個核心問題及其解決方法,并基于 Golang 反射技術,構建了一個簡易的 RPC 框架。

項目地址:Tiny-RPC

RPC

RPC(Remote Procedure Call),即遠程過程調用,可以理解成,服務 A 想調用不在同一內存空間的服務 B 的函數,由于不在一個內存空間,不能直接調用,需要通過網絡來表達調用的語義和傳達調用的數據。

服務端

RPC 服務端需要解決 2 個問題:

  • 由于客戶端傳送的是 RPC 函數名,服務端如何維護 函數名 與 函數實體 之間的映射
  • 服務端如何根據 函數名 實現對應的 函數實體 的調用

核心流程

  • 維護函數名到函數的映射
  • 在接收到來自客戶端的函數名、參數列表后,解析參數列表為反射值,并執行對應函數
  • 對函數執行結果進行編碼,并返回給客戶端

方法注冊

服務端需要維護 RPC 函數名到 RPC 函數實體的映射,我們可以使用 map 數據結構來維護映射關系。

type Server struct {
 addr string
 funcs map[string]reflect.Value
}

// Register a method via name
func (s *Server) Register(name string, f interface{}) {
 if _, ok := s.funcs[name]; ok {
 return
 }
 s.funcs[name] = reflect.ValueOf(f)
}

執行調用

一般來說,客戶端在調用 RPC 時,會將 函數名 和 參數列表 作為請求數據,發送給服務端。

由于我們使用了 map[string]reflect.Value 來維護函數名與函數實體之間的映射,則我們可以通過 Value.Call() 來調用與函數名相對應的函數。

package main

import (
 "fmt"
 "reflect"
)

func main() {
 // Register methods
 funcs := make(map[string]reflect.Value)
 funcs["add"] = reflect.ValueOf(add)

 // When receives client's request
 req := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
 vals := funcs["add"].Call(req)
 var rsp []interface{}
 for _, val := range vals {
 rsp = append(rsp, val.Interface())
 }

 fmt.Println(rsp)
}

func add(a, b int) (int, error) {
 return a + b, nil
}

具體實現

由于篇幅的限制,此處沒有貼出服務端實現的具體代碼,細節請查看項目地址。

客戶端

RPC 客戶端需要解決 1 個問題:

  • 由于函數的具體實現在服務端,客戶端只有函數的原型,客戶端如何通過 函數原型 調用其 函數實體

核心流程

  • 對調用者傳入的函數參數進行編碼,并傳送給服務端
  • 對服務端響應數據進行解碼,并返回給調用者

生成調用

我們可以通過 reflect.MakeFunc 為指定的函數原型綁定一個函數實體。

package main

import (
 "fmt"
 "reflect"
)

func main() {
 add := func(args []reflect.Value) []reflect.Value {
 result := args[0].Interface().(int) + args[1].Interface().(int)
 return []reflect.Value{reflect.ValueOf(result)}
 }

 var addptr func(int, int) int
 container := reflect.ValueOf(&addptr).Elem()
 v := reflect.MakeFunc(container.Type(), add)
 container.Set(v)

 fmt.Println(addptr(1, 2))
}

具體實現

由于篇幅的限制,此處沒有貼出客戶端實現的具體代碼,細節請查看項目地址。

數據傳輸格式

我們需要定義服務端與客戶端交互的數據格式。

type Data struct {
 Name string    // service name
 Args []interface{} // request's or response's body except error
 Err string    // remote server error
}

與交互數據相對應的編碼與解碼函數。

func encode(data Data) ([]byte, error) {
 var buf bytes.Buffer
 encoder := gob.NewEncoder(&buf)
 if err := encoder.Encode(data); err != nil {
 return nil, err
 }
 return buf.Bytes(), nil
}

func decode(b []byte) (Data, error) {
 buf := bytes.NewBuffer(b)
 decoder := gob.NewDecoder(buf)
 var data Data
 if err := decoder.Decode(&data); err != nil {
 return Data{}, err
 }
 return data, nil
}

同時,我們需要定義簡單的 TLV 協議(固定長度消息頭 + 變長消息體),規范數據的傳輸。

// Transport struct
type Transport struct {
 conn net.Conn
}

// NewTransport creates a transport
func NewTransport(conn net.Conn) *Transport {
 return &Transport{conn}
}

// Send data
func (t *Transport) Send(req Data) error {
 b, err := encode(req) // Encode req into bytes
 if err != nil {
 return err
 }
 buf := make([]byte, 4+len(b))
 binary.BigEndian.PutUint32(buf[:4], uint32(len(b))) // Set Header field
 copy(buf[4:], b)                  // Set Data field
 _, err = t.conn.Write(buf)
 return err
}

// Receive data
func (t *Transport) Receive() (Data, error) {
 header := make([]byte, 4)
 _, err := io.ReadFull(t.conn, header)
 if err != nil {
 return Data{}, err
 }
 dataLen := binary.BigEndian.Uint32(header) // Read Header filed
 data := make([]byte, dataLen)       // Read Data Field
 _, err = io.ReadFull(t.conn, data)
 if err != nil {
 return Data{}, err
 }
 rsp, err := decode(data) // Decode rsp from bytes
 return rsp, err
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

齐齐哈尔市| 三台县| 夹江县| 公主岭市| 玉山县| 集安市| 乐清市| 交城县| 望奎县| 嘉黎县| 石门县| 龙井市| 舒城县| 文山县| 万安县| 景洪市| 榆树市| 壤塘县| 武强县| 贵港市| 华阴市| 甘孜| 石景山区| 金溪县| 铁力市| 平阳县| 昭平县| 辰溪县| 筠连县| 藁城市| 涞水县| 榆林市| 海口市| 无棣县| 红安县| 扎鲁特旗| 仁布县| 鹰潭市| 西充县| 满洲里市| 盐源县|