真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

2.微服務(wù)--RPC

1.RPC簡(jiǎn)介

1.遠(yuǎn)程過程調(diào)用(Remote Procedure Call,RPC)是一個(gè)計(jì)算機(jī)通信協(xié)議。
2.該協(xié)議允許運(yùn)行于一臺(tái)計(jì)算機(jī)的程序調(diào)用另一臺(tái)計(jì)算機(jī)的子程序,而程序員無需額外地為這個(gè)交互作用編程。
3.如果涉及的軟件采用面向?qū)ο缶幊?,那么遠(yuǎn)程過程調(diào)用也可稱為遠(yuǎn)程調(diào)用或遠(yuǎn)程方法調(diào)用。

2.流行的RPC框架的對(duì)比

2.微服務(wù)--RPC

建鄴網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),建鄴網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為建鄴上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的建鄴做網(wǎng)站的公司定做!

3.golang中如何實(shí)現(xiàn)RPC

Golang中實(shí)現(xiàn)RPC比較簡(jiǎn)單,官方提供了封裝好的庫(kù),還有第三方庫(kù)。

官方庫(kù):net/rpc
1.net/rpc庫(kù)使用encoding/gob進(jìn)行編碼
2.支持tcp和http數(shù)據(jù)傳輸方式
3.由于其他語言不支持gob編解碼方式,所以golang的RPC只支持golang開發(fā)的服務(wù)端與客戶端的交互

官方庫(kù):net/jsonrpc
1.jsonrpc采用JSON進(jìn)行數(shù)據(jù)編解碼,因而支持跨語言調(diào)用。
2.jsonrpc庫(kù)是基于tcp協(xié)議實(shí)現(xiàn)的,暫不支持http傳輸方式。

golang的RPC必須符合四個(gè)條件才可以:
1.結(jié)構(gòu)體字段首字母要大寫,要跨域訪問,所以大寫。
2.函數(shù)名必須首字母大寫。
3.函數(shù)第一個(gè)參數(shù)是接收參數(shù),第二個(gè)參數(shù)是返回給客戶端參數(shù),必須是指針類型。
4.函數(shù)必須有一個(gè)返回值err。

3.1示例1

golang實(shí)現(xiàn)RPC程序,實(shí)現(xiàn)求矩形面積和周長(zhǎng)
//rpcClient/server.go

package main

import (
    "log"
    "net/http"
    "net/rpc"
)

//服務(wù)端,求舉行面積和周長(zhǎng)

//聲明矩形對(duì)象
type Rect struct {

}

//聲明參數(shù)結(jié)構(gòu)體,字段首字母大寫
type Param struct {
    Width,Height int
}
//golang的RPC必須符合4個(gè)條件才可以
//? 結(jié)構(gòu)體字段首字母要大寫,要跨域訪問,所以大寫
//? 函數(shù)名必須首字母大寫(可以序列號(hào)導(dǎo)出的)
//? 函數(shù)第一個(gè)參數(shù)是接收參數(shù),第二個(gè)參數(shù)是返回給客戶端參數(shù),必須是指針類型
//? 函數(shù)必須有一個(gè)返回值error

//定義求矩形面積的方法
func (r Rect) Area(p Param,ret *int)  error{
    *ret = p.Width * p.Height
    return nil
}
//定義求矩形周長(zhǎng)的方法
func (r Rect) Perimeter(p Param,ret *int)  error{
    *ret = (p.Width + p.Height)*2
    return nil
}

func main()  {
    //1.注冊(cè)服務(wù)
    rect := new(Rect)
    rpc.Register(rect)
    //2.把服務(wù)處理綁定到http協(xié)議上
    rpc.HandleHTTP()
    //3.監(jiān)聽服務(wù),等待客戶端調(diào)用請(qǐng)求面積和周長(zhǎng)的方法
    err := http.ListenAndServe(":8080",nil)
    if err != nil{
        log.Fatal(err)
    }
}
//rpcServer/client.go
package main

import (
    "fmt"
    "log"
    "net/rpc"
)

//聲明參數(shù)結(jié)構(gòu)體,字段首字母大寫
type Params struct {
    Width,Height int
}
//調(diào)用服務(wù)
func main()  {
    //1.鏈接遠(yuǎn)程RPC服務(wù)
    rp,err := rpc.DialHTTP("tcp","127.0.0.1:8080")
    if err != nil{
        log.Fatal(err)
    }
    //2.調(diào)用遠(yuǎn)程方法
    //定義接收服務(wù)端傳回來的計(jì)算結(jié)果的變量
    ret := 0
    //求矩形面積
    err2 := rp.Call("Rect.Area",Params{50,10},&ret)
    if err2 != nil{
        log.Fatal(err2)
    }
    fmt.Println("面積:",ret)

    //求矩形周長(zhǎng)
    err3 := rp.Call("Rect.Perimeter",Params{50,10},&ret)
    if err3 != nil{
        log.Fatal(err3)
    }
    fmt.Println("周長(zhǎng):",ret)
}

2.微服務(wù)--RPC
2.微服務(wù)--RPC

3.2示例2

模仿前面例題,自己實(shí)現(xiàn) RPC 程序,服務(wù)端接收 2 個(gè)參數(shù),可以做乘法運(yùn)算,也可以做商和余數(shù)的運(yùn)算,客戶端進(jìn)行傳參和訪問,得到結(jié)果如下:
 9*2 = 18
 9/2,商=4,余數(shù)=1

 下面使用net/rpc/jsonrpc庫(kù)通過json格式編碼解碼,支持跨語言調(diào)用
rpcServer/server.go

package main

import (
    "errors"
    "fmt"
    "log"
    "net"
    "net/rpc"
    "net/rpc/jsonrpc"
)

//結(jié)構(gòu)體,用于注冊(cè)的
type Arith struct {

}

//聲明參數(shù)結(jié)構(gòu)體
type ArithRequest struct {
    A,B int
}

//返回給客戶端的結(jié)果
type ArithResponse struct {
    //乘積
    Pro int
    //商
    Quo int
    //余數(shù)
    Rem int
}

//乘法
func (a *Arith) Multiply(req ArithRequest,res *ArithResponse) error  {
    res.Pro = req.A * req.B
    return nil
}
//商和余數(shù)
func (a *Arith) Divide(req ArithRequest,res *ArithResponse) error  {
    if req.B == 0{
        return errors.New("除數(shù)不能為0")

    }
    //商
    res.Quo = req.A/req.B
    //余數(shù)
    res.Rem = req.A%req.B
    return nil

}
func main()  {
    rpc.Register(new(Arith))
    lis,err := net.Listen("tcp",":8080")
    if err != nil{
        log.Fatal(err)
    }
    //循環(huán)監(jiān)聽服務(wù)
    for{
        conn,err := lis.Accept()
        if err != nil{
            continue
        }
        go func(conn net.Conn) {
            fmt.Println("new client")
            jsonrpc.ServeConn(conn)
        }(conn)
    }
}
rpcClient/client.go

package main

import (
    "fmt"
    "log"
    "net/rpc/jsonrpc"
)

//聲明參數(shù)結(jié)構(gòu)體
type ArithRequest struct {
    A,B int
}

//返回給客戶端的結(jié)果
type ArithResponse struct {
    //乘積
    Pro int
    //商
    Quo int
    //余數(shù)
    Rem int
}
//調(diào)用服務(wù)
func main()  {
    conn,err := jsonrpc.Dial("tcp",":8080")
    if err != nil{
        log.Fatal(err)
    }
    req := ArithRequest{9,2}
    var res ArithResponse
    err2 := conn.Call("Arith.Multiply", req, &res)
    if err2 != nil {
        log.Fatal(err2)
    }
    fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro)
    err3 := conn.Call("Arith.Divide", req, &res)
    if err3 != nil {
        log.Fatal(err3)
    }
    fmt.Printf("%d / %d 商 %d,余數(shù) = %d\n", req.A, req.B, res.Quo, res.Rem)
}

2.微服務(wù)--RPC
2.微服務(wù)--RPC

3.3RPC調(diào)用流程

2.微服務(wù)--RPC

1.微服務(wù)架構(gòu)下數(shù)據(jù)交互一般是對(duì)內(nèi)RPC,對(duì)外REST。
2.將業(yè)務(wù)按功能模塊拆分到各個(gè)微服務(wù),具有提高項(xiàng)目協(xié)作效率、降低模塊耦合度、提高系統(tǒng)可用性等優(yōu)點(diǎn),但是開發(fā)門檻比較高,比如RPC框架的時(shí)候,后期的服務(wù)監(jiān)控等工作。
3.一般情況下,我們會(huì)將功能代碼在本地直接調(diào)用,微服務(wù)架構(gòu)下,我們需要將這個(gè)函數(shù)作為單獨(dú)的服務(wù)運(yùn)行,客戶端通過網(wǎng)絡(luò)調(diào)用。

3.5自己實(shí)現(xiàn)RPC調(diào)用庫(kù)(類似于net/rpc、net/rpc/jsonrpc)

3.5.1網(wǎng)絡(luò)傳輸數(shù)據(jù)格式

成熟的RPC框架會(huì)有自定義傳輸協(xié)議,這里網(wǎng)絡(luò)傳輸格式定義如下:
前面是固定長(zhǎng)度消息頭,后面是變長(zhǎng)消息體。

2.微服務(wù)--RPC

//會(huì)話中讀寫數(shù)據(jù)測(cè)試

//rpc/session.go
package rpc

import (
    "encoding/binary"
    "io"
    "net"
)

//測(cè)試網(wǎng)絡(luò)中讀寫數(shù)據(jù)的情況

//會(huì)話連接的結(jié)構(gòu)體
type Session struct {
    conn net.Conn
}

//構(gòu)造方法
func NewSession(conn net.Conn) *Session {
    return &Session{conn:conn}
}

//向連接中寫數(shù)據(jù)
func (s *Session) Write(data []byte) error {
    //定義寫數(shù)據(jù)的格式

    //4字節(jié)頭部+可變體的長(zhǎng)度
    buf := make([]byte,4+len(data))
    //寫入頭部,記錄數(shù)據(jù)長(zhǎng)度
    binary.BigEndian.PutUint32(buf[:4],uint32(len(data)))
    //將整個(gè)數(shù)據(jù),放在索引4的后面
    copy(buf[4:],data)
    _,err := s.conn.Write(buf)
    if err != nil{
        return err
    }
    return nil
}

//從連接中讀數(shù)據(jù)
func (s *Session) Read() ([]byte,error)  {
    //讀取頭部記錄的長(zhǎng)度
    header := make([]byte, 4)
    //按長(zhǎng)度讀取頭部消息
    _,err := io.ReadFull(s.conn, header)
    if err != nil{
        return nil,err
    }

    //根據(jù)頭部信息,讀取數(shù)據(jù)長(zhǎng)度
    dataLen := binary.BigEndian.Uint32(header)
    data := make([]byte,dataLen)
    //讀取到的數(shù)據(jù)存到data中
    _,err = io.ReadFull(s.conn, data)
    if err != nil{
        return nil,err
    }
    return data,nil
}
//rpc/session_test.go

package rpc

import (
    "fmt"
    "net"
    "sync"
    "testing"
)

func TestSession_ReadWriter(t *testing.T)  {
    //定義地址
    addr := "127.0.0.1:8000"
    my_data := "hello lili"
    wg := sync.WaitGroup{}
    wg.Add(2)

    //寫數(shù)據(jù)的協(xié)成
    go func() {
        defer wg.Done()
        lis,err := net.Listen("tcp", addr)
        if err != nil{
            t.Fatal(err)
        }
        conn,_ := lis.Accept()
        s:= NewSession(conn)
        err = s.Write([]byte(my_data))
        if err != nil{
            t.Fatal(err)
        }
    }()
    //讀數(shù)據(jù)的協(xié)成
    go func() {
        defer wg.Done()
        conn,err := net.Dial("tcp", addr)
        if err != nil{
            t.Fatal(err)
        }
        s:= NewSession(conn)
        data,err := s.Read()
        if err!= nil{}
        t.Fatal(err)

        //最后一層校驗(yàn)
        if string(data) != my_data{
            t.Fatal(err)
        }

        fmt.Println("讀取到的數(shù)據(jù)為:",string(data))
    }()
}
測(cè)試結(jié)果:
 rpc go test -v            
=== RUN   TestSession_ReadWriter
--- PASS: TestSession_ReadWriter (0.00s)
PASS
ok      _/Users/tongchao/Desktop/gopath/src/test/rpc    0.008s
?  rpc 

3.5.2gob編碼/解碼

//codec.go
package rpc

import (
    "bytes"
    "encoding/gob"
)

//定義RPC交互的數(shù)據(jù)結(jié)構(gòu)

type RPCData struct {
    //訪問的函數(shù)
    Name string
    //訪問時(shí)的參數(shù)
    Args []interface{}
}

//編碼
func encode(data RPCData) ([]byte, error)  {
    //得到字節(jié)數(shù)組的編碼器
    var buf bytes.Buffer
    bufEnc := gob.NewEncoder(&buf)
    //編碼器對(duì)數(shù)據(jù)編碼
    if err := bufEnc.Encode(data); err != nil{
        return nil,err
    }
    return buf.Bytes(),nil
}

//解碼
func decode(b []byte) (RPCData,error)  {
    buf := bytes.NewBuffer(b)
    //得到字節(jié)數(shù)組的解碼器
    bufDec := gob.NewDecoder(buf)
    //解碼器對(duì)數(shù)據(jù)解碼
    var data RPCData
    if err:= bufDec.Decode(&data);err != nil{
        return data,err
    }
    return data,nil
}
//codec_test.go
package rpc
import (
    "fmt"
    "testing"
)
func TestCode(t *testing.T)  {
    args := make([]interface{},0)
    data := RPCData{
        Name: "lili",
        Args: args,
    }
    encodeData,err := encode(data)
    if err != nil{
        fmt.Println(err)
    }
    fmt.Printf("encodeData:%v\n",encodeData)

    decodeData,err := decode(encodeData)
    if err != nil{
        fmt.Println(err)
    }
    fmt.Printf("decodeData:%v\n",decodeData)
}

結(jié)果:
=== RUN   TestCode
encodeData:[40 255 129 3 1 1 7 82 80 67 68 97 116 97 1 255 130 0 1 2 1 4 78 97 109 101 1 12 0 1 4 65 114 103 115 1 255 132 0 0 0 28 255 131 2 1 1 14 91 93 105 110 116 101 114 102 97 99 101 32 123 125 1 255 132 0 1 16 0 0 9 255 130 1 4 108 105 108 105 0]
decodeData:{lili []}
--- PASS: TestCode (0.00s)
PASS

Process finished with exit code 0

本文名稱:2.微服務(wù)--RPC
網(wǎng)頁(yè)URL:http://weahome.cn/article/pppiej.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部