最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)文章

  • Go strconv包實(shí)現(xiàn)字符串和基本數(shù)據(jù)類型轉(zhuǎn)換的實(shí)例詳解

    Go strconv包實(shí)現(xiàn)字符串和基本數(shù)據(jù)類型轉(zhuǎn)換的實(shí)例詳解

    在Go語(yǔ)言(Golang)的編程實(shí)踐中,strconv包是一個(gè)非常重要的標(biāo)準(zhǔn)庫(kù),它提供了在基本數(shù)據(jù)類型(如整型、浮點(diǎn)型、布爾型)和字符串之間的轉(zhuǎn)換功能,本文給大家介紹了關(guān)于Go語(yǔ)言字符串轉(zhuǎn)換strconv,需要的朋友可以參考下
    2024-09-09
  • golang?gorm學(xué)習(xí)之如何指定數(shù)據(jù)表

    golang?gorm學(xué)習(xí)之如何指定數(shù)據(jù)表

    在sql中首先要指定是從哪張表中查詢,所以這篇文章小編就來(lái)帶大家一起看一下gorm是如何根據(jù)model來(lái)自動(dòng)解析表名的,感興趣的小伙伴可以了解下
    2023-08-08
  • 使用Golang創(chuàng)建單獨(dú)的WebSocket會(huì)話

    使用Golang創(chuàng)建單獨(dú)的WebSocket會(huì)話

    WebSocket是一種在Web開(kāi)發(fā)中非常常見(jiàn)的通信協(xié)議,它提供了雙向、持久的連接,適用于實(shí)時(shí)數(shù)據(jù)傳輸和實(shí)時(shí)通信場(chǎng)景,本文將介紹如何使用 Golang 創(chuàng)建單獨(dú)的 WebSocket 會(huì)話,包括建立連接、消息傳遞和關(guān)閉連接等操作,需要的朋友可以參考下
    2023-12-12
  • 在Go中復(fù)制文件最流行的3種方法

    在Go中復(fù)制文件最流行的3種方法

    今天小編就為大家分享一篇關(guān)于在Go中復(fù)制文件最流行的3種方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • go語(yǔ)言實(shí)現(xiàn)并發(fā)網(wǎng)絡(luò)爬蟲(chóng)的示例代碼

    go語(yǔ)言實(shí)現(xiàn)并發(fā)網(wǎng)絡(luò)爬蟲(chóng)的示例代碼

    本文主要介紹了go語(yǔ)言實(shí)現(xiàn)并發(fā)網(wǎng)絡(luò)爬蟲(chóng)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • GoLang中生成UUID唯一標(biāo)識(shí)的實(shí)現(xiàn)方法

    GoLang中生成UUID唯一標(biāo)識(shí)的實(shí)現(xiàn)方法

    UUID是讓分散式系統(tǒng)中的所有元素,都能有唯一的辨識(shí)信息,本文主要介紹了GoLang中生成UUID唯一標(biāo)識(shí)的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-08-08
  • Golang 使用Map實(shí)現(xiàn)去重與set的功能操作

    Golang 使用Map實(shí)現(xiàn)去重與set的功能操作

    這篇文章主要介紹了Golang 使用 Map 實(shí)現(xiàn)去重與 set 的功能操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Golang易錯(cuò)知識(shí)點(diǎn)匯總

    Golang易錯(cuò)知識(shí)點(diǎn)匯總

    這篇文章匯總了在開(kāi)發(fā)和刷面試題過(guò)程中遇到的Golang容易搞錯(cuò)的知識(shí)點(diǎn),關(guān)鍵部分也都為大家寫(xiě)了代碼示例,感興趣的小伙伴可以了解一下
    2022-09-09
  • 詳解Go語(yǔ)言單元測(cè)試中如何解決MySQL存儲(chǔ)依賴問(wèn)題

    詳解Go語(yǔ)言單元測(cè)試中如何解決MySQL存儲(chǔ)依賴問(wèn)題

    MySQL?存儲(chǔ)就是一個(gè)非常常見(jiàn)的外部依賴,這篇文章主要來(lái)和大家一起探討在?Go?語(yǔ)言中編寫(xiě)單元測(cè)試時(shí),如何解決?MySQL?存儲(chǔ)依賴,需要的可以參考一下
    2023-07-07
  • go解析svn log生成的xml格式的文件

    go解析svn log生成的xml格式的文件

    這篇文章主要介紹了go解析svn log生成的xml格式的文件的方法,非常的實(shí)用,有需要的小伙伴可以參考下。
    2015-04-04

最新評(píng)論

洮南市| 九江县| 雅江县| 定西市| 吴川市| 崇仁县| 五家渠市| 华蓥市| 商洛市| 炎陵县| 桃园市| 阿克陶县| 安吉县| 佛冈县| 囊谦县| 根河市| 古浪县| 法库县| 额敏县| 卢龙县| 洱源县| 双柏县| 丁青县| 左权县| 江城| 临西县| 建水县| 友谊县| 南通市| 麟游县| 明水县| 天全县| 彰化县| 婺源县| 山阳县| 兴和县| 万载县| 潞西市| 三穗县| 南平市| 大厂|