精品专区-精品自拍9-精品自拍三级乱伦-精品自拍视频-精品自拍视频曝光-精品自拍小视频

網站建設資訊

NEWS

網站建設資訊

Golang中怎么實現一個RPC功能

今天就跟大家聊聊有關Golang中怎么實現一個RPC功能,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

創新互聯建站來電聯系:18980820575,為您提供成都網站建設網頁設計及定制高端網站建設服務,創新互聯建站網頁制作領域十余年,包括成都玻璃隔斷等多個行業擁有多年的網站設計經驗,選擇創新互聯建站,為網站保駕護航。

客戶端:服務調用發起方,又稱之為服務消費者 服務器:遠端計算機上運行的程序,其中包含客戶端要調用和訪問的方法 客戶端存根:存放服務器端的地址,端口消息,將客戶端的請求參數打包成網絡消息,發送給服務器方。接收服務器方返回的數據包。該段程序運行在客戶端。 服務端存根:接收客戶端發送的數據包,解析數據包,調用數據包,調用具體的服務方法,將調用結果打包發送給客戶端一方。該段程序運行在服務端。

工作過程:

1、客戶端想要發起一個遠程過程調用,首先通過調用本地客戶端Stub程序的方式調用想要使用的功能方法名;

2、客戶端Stub程序接收到了客戶端的功能調用請求,將客戶端請求調用的方法名,攜帶的參數等信息做序列化操作,并打包成數據包。

3、客戶端Stub查找到遠程服務器程序的IP地址,調用Socket通信協議,通過網絡發送給服務端。

4、服務端Stub程序接收到客戶端發送的數據包信息,并通過約定好的協議將數據進行反序列化,得到請求的方法名和請求參數等信息。

5、服務端Stub程序準備相關數據,調用本地Server對應的功能方法進行,并傳入相應的參數,進行業務處理。

6、服務端程序根據已有業務邏輯執行調用過程,待業務執行結束,將執行結果返回給服務端Stub程序。

7、服務端Stub程序將程序調用結果按照約定的協議進行序列化,并通過網絡發送回客戶端Stub程序。

8、客戶端Stub程序接收到服務端Stub發送的返回數據,對數據進行反序列化操作,并將調用返回的數據傳遞給客戶端請求發起者。

9、客戶端請求發起者得到調用結果,整個RPC調用過程結束。

RPC涉及到的相關技術 通過上文一系列的文字描述和講解,我們已經了解了RPC的由來和RPC整個調用過程。我們可以看到RPC是一系列操作的集合,其中涉及到很多對數據的操作,以及網絡通信。因此,我們對RPC中涉及到的技術做一個總結和分析:

1、動態代理技術: 上文中我們提到的Client Stub和Sever Stub程序,在具體的編碼和開發實踐過程中,都是使用動態代理技術自動生成的一段程序。

2、序列化和反序列化: 在RPC調用的過程中,我們可以看到數據需要在一臺機器上傳輸到另外一臺機器上。在互聯網上,所有的數據都是以字節的形式進行傳輸的。而我們在編程的過程中,往往都是使用數據對象,因此想要在網絡上將數據對象和相關變量進行傳輸,就需要對數據對象做序列化和反序列化的操作。

序列化:把對象轉換為字節序列的過程稱為對象的序列化,也就是編碼的過程。

反序列化:把字節序列恢復為對象的過程稱為對象的反序列化,也就是解碼的過程。

服務定義及暴漏:

func (t *T) MethodName(request T1,response *T2) error 上述代碼是go語言官方給出的對外暴露的服務方法的定義標準,其中包含了主要的幾條規則,分別是: 1、對外暴露的方法有且只能有兩個參數,這個兩個參數只能是輸出類型或內建類型,兩種類型中的一種。 2、方法的第二個參數必須是指針類型。 3、方法的返回類型為error。 4、方法的類型是可輸出的。 * 5、方法本身也是可輸出的。

type MathUtil struct{}//該方法向外暴露:提供計算圓形面積的服務
func (mu *MathUtil) CalculateCircleArea(req float32, resp *float32) error {
    *resp = math.Pi * req * req //圓形的面積 s = π * r * r
    return nil //返回類型
}

代碼講解: 在上述的案例中,我們可以看到: 1、Calculate方法是服務對象MathUtil向外提供的服務方法,該方法用于接收傳入的圓形半徑數據,計算圓形面積并返回。 2、第一個參數req代表的是調用者(client)傳遞提供的參數。 3、第二個參數resp代表要返回給調用者的計算結果,必須是指針類型。 4、正常情況下,方法的返回值為是error,為nil。如果遇到異常或特殊情況,則error將作為一個字符串返回給調用者,此時,resp參數就不會再返回給調用者。

客戶端連接服務端:

client, err := rpc.DialHTTP("tcp", "localhost:8081")

if err != nil { 
panic(err.Error())
}

遠端方法調用 客戶端成功連接服務端以后,就可以通過方法調用調用服務端的方法,具體調用方法如下:

var req float32 //請求值 req = 3
var resp float32 //返回值 
err = client.Call("MathUtil.CalculateCircleArea", req, &resp) 
if err != nil { 
panic(err.Error()) 
} 
fmt.Println(resp)

上述的調用方法核心在于client.Call方法的調用,該方法有三個參數,第一個參數表示要調用的遠端服務的方法名,第二個參數是調用時要傳入的參數,第三個參數是調用要接收的返回值。 上述的Call方法調用實現的方式是同步的調用,除此之外,還有一種異步的方式可以實現調用。異步調用代碼實現如下:

var respSync *float32
//異步的調用方式 
syncCall := client.Go("MathUtil.CalculateCircleArea", req, &respSync, nil)
replayDone := <-syncCall.Done
fmt.Println(replayDone)
fmt.Println(*respSync)

代碼演示:

Go HTTPRPC

//server
package main


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


//使用 rpc http實現簡單的 rpc操作
type Args struct {
    A, B int
}


type Math int


func (m *Math) Multiply(args *Args, reply *int) error {
    *reply = args.A * args.B
    return nil
}


type Quotient struct {
    Quo, Rem int
}


func (m *Math) Divide(args *Args, quo *Quotient) error {
    if args.B == 0 {
        return errors.New("divide by zero")
    }


    quo.Quo = args.A / args.B


    quo.Rem = args.A % args.B


    return nil
}


func main() {
    math := new(Math)
    rpc.Register(math) //注冊rpc
    rpc.HandleHTTP()   //使用http rpc


    fmt.Println("rpc http server runing ....")
    err := http.ListenAndServe(":1234", nil)


    if err != nil {
        log.Println(err.Error())
    }
}

//client
package main


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


type Args struct {
    A, B int
}


type Quotient struct {
    Quo, Rem int
}


func main() {


    // fmt.Println(os.Args)


    // if len(os.Args) != 2 {
    //  fmt.Println("usage:", os.Args[0], "server")
    //  os.Exit(1)
    // }


    serverAddr := "127.0.0.1"


    client, err := rpc.DialHTTP("tcp", serverAddr+":1234")


    if err != nil {
        log.Println("dial err is ", err)
    }


    var reply int


    args := Args{1, 2}


    err = client.Call("Math.Multiply", args, &reply) //server method方法名要與server一致,寫錯后,將會提示服務不存在


    if err != nil {
        log.Println("call err ", err)
    }


    fmt.Printf("Math Multiply: %d * %d =%d \n", args.A, args.B, reply)


    var quo Quotient
    err = client.Call("Math.Divide", args, &quo)


    if err != nil {
        log.Println("divide err ", err)
    }
    fmt.Printf("Math Divide: %d / %d =%d remainder %d \n", args.A, args.B, quo.Quo, quo.Rem)


}

Go TcpRPC

//server
package main


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


type Math int


type Args struct {
    A, B int
}


func (m *Math) Multiply(args *Args, reply *int) error {


    *reply = args.A * args.B


    return nil
}


type Quotient struct {
    Quo, Rem int
}


func (m *Math) Divide(args *Args, quo *Quotient) error {


    if args.B == 0 {
        return errors.New("divide by zero")
    }


    quo.Quo = args.A / args.B
    quo.Rem = args.A % args.B


    return nil
}


func main() {


    math := new(Math)


    rpc.Register(math)


    tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")


    if err != nil {
        log.Println("Resolve Ip addr err ", err)
        return
    }


    listen, err := net.ListenTCP("tcp", tcpAddr)


    if err != nil {
        log.Println("listen err is ", err)
        return
    }


    for {
        server, err := listen.Accept()
        if err != nil {
            log.Println("accept err is ", err)
            continue
        }
        rpc.ServeConn(server)
    }
}

//client

package main


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


type Args struct {
    A, B int
}


type Quotient struct {
    Quo, Rem int
}


func main() {


    client, err := rpc.Dial("tcp", "127.0.0.1"+":1234")


    if err != nil {
        log.Println("rpc dial err :", err)
        return
    }


    args := Args{1, 2}
    var reply int
    err = client.Call("Math.Multiply", args, &reply)


    if err != nil {
        log.Println("multiply err ", err)
        return
    }


    fmt.Printf("multiply %d * %d = %d  \n", args.A, args.B, reply)


    var quo Quotient


    err = client.Call("Math.Divide", args, &quo)


    if err != nil {
        log.Println("Divite err is ", err)
        return
    }


    fmt.Printf("Divide %d / %d =%d ,rem %d", args.A, args.B, quo.Quo, quo.Rem)


}

Go JSONRPC

//server
package main


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




type Math int


type Args struct {
    A, B int
}


type Quotient struct {
    Quo, Rem int
}


func (m *Math)Multiply(args Args,reply *int) error{
    *reply=args.A*args.B


    return nil
}




func (m *Math)Divide(args Args,quo *Quotient) error{
    if args.B==0{
        return errors.New("divide by zreo")
    }


    quo.Quo=args.A/args.B
    quo.Rem=args.A%args.B
    
    return nil
}


func main(){


    math:=new(Math)


    rpc.Register(math)


    listenAddr,err:=net.ResolveTCPAddr("tcp",":1234")
    if err!=nil{
        log.Println("resove ip addr err is ",err)
        return
    }


    listen,err:=net.ListenTCP("tcp",listenAddr)


    if err!=nil{
        log.Println("listenTcp err ",err)
        return
    }


    for{
        conn,err:=listen.Accept()


        if err!=nil{
            log.Println("accept err is ",err)
            return
        }
        jsonrpc.ServeConn(conn)
    }
    
}

//client

package main


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


type Args struct {
    A, B int
}


type Quotient struct {
    Quo, Rem int
}


func main() {


    client, err := jsonrpc.Dial("tcp", "127.0.0.1"+":1234")


    if err != nil {
        log.Println("rpc dial err :", err)
        return
    }


    args := Args{1, 2}
    var reply int
    err = client.Call("Math.Multiply", args, &reply)


    if err != nil {
        log.Println("multiply err ", err)
        return
    }


    fmt.Printf("multiply %d * %d = %d  \n", args.A, args.B, reply)


    var quo Quotient


    err = client.Call("Math.Divide", args, &quo)


    if err != nil {
        log.Println("Divite err is ", err)
        return
    }


    fmt.Printf("Divide %d / %d =%d ,rem %d", args.A, args.B, quo.Quo, quo.Rem)


}

看完上述內容,你們對Golang中怎么實現一個RPC功能有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注創新互聯行業資訊頻道,感謝大家的支持。


網頁標題:Golang中怎么實現一個RPC功能
新聞來源:http://m.jcarcd.cn/article/jgsjej.html
主站蜘蛛池模板: 国产羞羞影院在 | 日韩欧美一区 | 韩剧大全 | 韩国十九 | 91香蕉国产在线 | 精品乱伦中文日本 | 成人影院免 | 福利社午夜影院 | 91社区福利| 97成人抖音| 日本强伦姧 | 日本国产精品二区 | 日韩激情国产 | 欠久福利小视频 | 成人影片导航 | 日本不卡a | 国产精品12 | 国产精品短篇二区 | 91兔女郎在线视频 | 国产喷水福利 | 日本免费| 国产美女遭| 日本最新成人精品 | 97亚洲99 | 精品熟女中文字幕 | 精品成人免费 | 国产午夜手 | 精品国产污免 | 精品美女福利视 | 日韩午夜免费免费 | 韩国不卡午夜 | 精品一区三 | 午夜福利日韩精品 | 国产欧美日韩一 | 国产精品一区乱码在 | 激情图区在线 | 国产国产 | 国产在线拍偷自揄 | 国产又色又爽又黄 | 精品日本亚洲影视 | 国产精品网址 |