欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go實(shí)現(xiàn)簡(jiǎn)易R(shí)PC框架的方法步驟

 更新時(shí)間:2019年03月13日 14:25:14   作者:Jiahonzheng  
本文旨在講述 RPC 框架設(shè)計(jì)中的幾個(gè)核心問(wèn)題及其解決方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

本文旨在講述 RPC 框架設(shè)計(jì)中的幾個(gè)核心問(wèn)題及其解決方法,并基于 Golang 反射技術(shù),構(gòu)建了一個(gè)簡(jiǎn)易的 RPC 框架。

項(xiàng)目地址:Tiny-RPC

RPC

RPC(Remote Procedure Call),即遠(yuǎn)程過(guò)程調(diào)用,可以理解成,服務(wù) A 想調(diào)用不在同一內(nèi)存空間的服務(wù) B 的函數(shù),由于不在一個(gè)內(nèi)存空間,不能直接調(diào)用,需要通過(guò)網(wǎng)絡(luò)來(lái)表達(dá)調(diào)用的語(yǔ)義和傳達(dá)調(diào)用的數(shù)據(jù)。

服務(wù)端

RPC 服務(wù)端需要解決 2 個(gè)問(wèn)題:

  • 由于客戶端傳送的是 RPC 函數(shù)名,服務(wù)端如何維護(hù) 函數(shù)名 與 函數(shù)實(shí)體 之間的映射
  • 服務(wù)端如何根據(jù) 函數(shù)名 實(shí)現(xiàn)對(duì)應(yīng)的 函數(shù)實(shí)體 的調(diào)用

核心流程

  • 維護(hù)函數(shù)名到函數(shù)的映射
  • 在接收到來(lái)自客戶端的函數(shù)名、參數(shù)列表后,解析參數(shù)列表為反射值,并執(zhí)行對(duì)應(yīng)函數(shù)
  • 對(duì)函數(shù)執(zhí)行結(jié)果進(jìn)行編碼,并返回給客戶端

方法注冊(cè)

服務(wù)端需要維護(hù) RPC 函數(shù)名到 RPC 函數(shù)實(shí)體的映射,我們可以使用 map 數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)映射關(guān)系。

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)
}

執(zhí)行調(diào)用

一般來(lái)說(shuō),客戶端在調(diào)用 RPC 時(shí),會(huì)將 函數(shù)名 和 參數(shù)列表 作為請(qǐng)求數(shù)據(jù),發(fā)送給服務(wù)端。

由于我們使用了 map[string]reflect.Value 來(lái)維護(hù)函數(shù)名與函數(shù)實(shí)體之間的映射,則我們可以通過(guò) Value.Call() 來(lái)調(diào)用與函數(shù)名相對(duì)應(yīng)的函數(shù)。

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
}

具體實(shí)現(xiàn)

由于篇幅的限制,此處沒(méi)有貼出服務(wù)端實(shí)現(xiàn)的具體代碼,細(xì)節(jié)請(qǐng)查看項(xiàng)目地址。

客戶端

RPC 客戶端需要解決 1 個(gè)問(wèn)題:

  • 由于函數(shù)的具體實(shí)現(xiàn)在服務(wù)端,客戶端只有函數(shù)的原型,客戶端如何通過(guò) 函數(shù)原型 調(diào)用其 函數(shù)實(shí)體

核心流程

  • 對(duì)調(diào)用者傳入的函數(shù)參數(shù)進(jìn)行編碼,并傳送給服務(wù)端
  • 對(duì)服務(wù)端響應(yīng)數(shù)據(jù)進(jìn)行解碼,并返回給調(diào)用者

生成調(diào)用

我們可以通過(guò) reflect.MakeFunc 為指定的函數(shù)原型綁定一個(gè)函數(shù)實(shí)體。

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))
}

具體實(shí)現(xiàn)

由于篇幅的限制,此處沒(méi)有貼出客戶端實(shí)現(xiàn)的具體代碼,細(xì)節(jié)請(qǐng)查看項(xiàng)目地址

數(shù)據(jù)傳輸格式

我們需要定義服務(wù)端與客戶端交互的數(shù)據(jù)格式。

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

與交互數(shù)據(jù)相對(duì)應(yīng)的編碼與解碼函數(shù)。

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
}

同時(shí),我們需要定義簡(jiǎn)單的 TLV 協(xié)議(固定長(zhǎng)度消息頭 + 變長(zhǎng)消息體),規(guī)范數(shù)據(jù)的傳輸。

// 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
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用dep 配置golang 開(kāi)發(fā)環(huán)境的操作方法

    使用dep 配置golang 開(kāi)發(fā)環(huán)境的操作方法

    下面小編就為大家?guī)?lái)一篇使用dep 配置golang 開(kāi)發(fā)環(huán)境的操作方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • golang執(zhí)行命令操作 exec.Command

    golang執(zhí)行命令操作 exec.Command

    這篇文章主要介紹了golang執(zhí)行命令操作 exec.Command,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go語(yǔ)言分布式id生成器及分布式鎖介紹

    go語(yǔ)言分布式id生成器及分布式鎖介紹

    這篇文章主要為大家介紹了go語(yǔ)言分布式id生成器及分布式鎖介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 詳解Go程序添加遠(yuǎn)程調(diào)用tcpdump功能

    詳解Go程序添加遠(yuǎn)程調(diào)用tcpdump功能

    這篇文章主要介紹了go程序添加遠(yuǎn)程調(diào)用tcpdump功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • Go語(yǔ)言反射reflect.Value實(shí)現(xiàn)方法的調(diào)用

    Go語(yǔ)言反射reflect.Value實(shí)現(xiàn)方法的調(diào)用

    本文主要介紹了Go語(yǔ)言反射reflect.Value實(shí)現(xiàn)方法的調(diào)用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Go語(yǔ)言fmt庫(kù)詳解與應(yīng)用實(shí)例(格式化輸入輸出功能)

    Go語(yǔ)言fmt庫(kù)詳解與應(yīng)用實(shí)例(格式化輸入輸出功能)

    fmt庫(kù)是Go語(yǔ)言中一個(gè)強(qiáng)大而靈活的庫(kù),提供了豐富的格式化輸入輸出功能,通過(guò)本文的介紹和實(shí)例演示,相信你對(duì)fmt庫(kù)的使用有了更深的理解,感興趣的朋友一起看看吧
    2023-10-10
  • Go語(yǔ)言實(shí)現(xiàn)牛頓法求平方根函數(shù)的案例

    Go語(yǔ)言實(shí)現(xiàn)牛頓法求平方根函數(shù)的案例

    這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)牛頓法求平方根函數(shù)的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go語(yǔ)言獲取系統(tǒng)盤(pán)符的方法

    go語(yǔ)言獲取系統(tǒng)盤(pán)符的方法

    這篇文章主要介紹了go語(yǔ)言獲取系統(tǒng)盤(pán)符的方法,涉及Go語(yǔ)言調(diào)用winapi獲取系統(tǒng)硬件信息的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • GoLang中panic和recover作用詳解

    GoLang中panic和recover作用詳解

    panic?和?recover?是?Go?語(yǔ)言中用于處理異常和錯(cuò)誤的機(jī)制,能夠幫助我們應(yīng)對(duì)意外情況并使程序更加健壯,這篇文章主要介紹了GoLang中panic和recover作用詳解,需要的朋友可以參考下
    2024-05-05
  • golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題

    golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題

    這篇文章主要介紹了golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評(píng)論