1. 程式人生 > >用Go語言解釋什麼是RPC

用Go語言解釋什麼是RPC

簡介

遠端過程呼叫(英語:Remote Procedure Call,縮寫為 RPC)是一個計算機通訊協議。該協議允許運行於一臺計算機的程式呼叫另一臺計算機的子程式,而程式設計師無需額外地為這個互動作用程式設計。

Go語言使用RPC

標準庫net/rpc包是怎麼描述的:

package rpc
import "net/rpc"

rpc包提供了通過網路或其他I/O連線對一個物件的匯出方法的訪問。服務端註冊一個物件,使它作為一個服務被暴露,服務的名字是該物件的型別名。註冊之後,物件的匯出方法就可以被遠端訪問。服務端可以註冊多個不同型別的物件(服務),但註冊具有相同型別的多個物件是錯誤的。

只有滿足如下標準的方法才能用於遠端訪問,其餘方法會被忽略:
- 方法是匯出的
- 方法有兩個引數,都是匯出型別或內建型別
- 方法的第二個引數是指標
- 方法只有一個error介面型別的返回值

事實上,方法必須看起來像這樣:
func (t *T) MethodName(argType T1, replyType *T2) error
其中T、T1和T2都能被encoding/gob包序列化。這些限制即使使用不同的編解碼器也適用。(未來,對定製的編解碼器可能會使用較寬鬆一點的限制)

方法的第一個引數代表呼叫者提供的引數;第二個引數代表返回給呼叫者的引數。方法的返回值,如果非nil,將被作為字串回傳,在客戶端看來就和errors.New建立的一樣。如果返回了錯誤,回覆的引數將不會被髮送給客戶端。

服務端可能會單個連線上呼叫ServeConn管理請求。更典型地,它會建立一個網路監聽器然後呼叫Accept;或者,對於HTTP監聽器,呼叫HandleHTTPhttp.Serve

想要使用服務的客戶端會建立一個連線,然後用該連線呼叫NewClient

更方便的函式Dial(DialHTTP)會在一個原始的連線(或HTTP連線)上依次執行這兩個步驟。

生成的Client型別值有兩個方法,Call和Go,它們的引數為要呼叫的服務和方法、一個包含引數的指標、一個用於接收接個的指標。

Call方法會等待遠端呼叫完成,而Go方法非同步的傳送呼叫請求並使用返回的Call結構體型別的Done通道欄位傳遞完成訊號。
除非設定了顯式的編解碼器,本包預設使用encoding/gob

包來傳輸資料。

然後標準庫也給出了一個例子:

data.go

package server

import (
    "errors"
)

type Args struct {
    A, B int
}
type Quotient struct {
    Quo, Rem int
}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error {
    *reply = args.A * args.B
    return nil
}
func (t *Arith) 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
}

分析:這是一個公共包,服務端和客戶端都有用到裡面的資料

client.go

package main

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

    "learn-rpc/data"
)

func main() {
    client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
    if err != nil {
        log.Fatal("dialing:", err)
    }
    // Synchronous call
    args := &data.Args{9, 9}
    var reply int
    err = client.Call("Arith.Multiply", args, &reply)
    if err != nil {
        log.Fatal("arith error:", err)
    }
    fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)
}

分析:客戶端程式,先獲得一個rpc.Client的結構,然後呼叫Call方法

server.go

package main

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

    "learn-rpc/data"
)

func main() {
    arith := new(data.Arith)
    rpc.Register(arith)
    rpc.HandleHTTP()
    l, e := net.Listen("tcp", ":1234")
    if e != nil {
        log.Fatal("listen error:", e)
    }
    http.Serve(l, nil)
}

分析:先呼叫Listen方法獲得Listen結構,接著呼叫將該結構傳給Serve方法即可開始監聽

注意:在執行程式時,要注意包路徑的問題,否則會編譯錯誤
先執行服務端,再執行客戶端