go語言--RPC

golang中的rpc

• RPC定義

RPC,Remote Procedure Call Protocol,遠程過程調用協議。RPC是一種通過網絡從遠程計算機程序上請求服務,但不需要了解底層網絡技術的一種協議。RPC協議基於某些傳輸協議(如TCP和UDP協議等)而存在,爲通信程序之間攜帶信息數據。

在傳統計算機編程語言中,譬如C和C++,實現RPC是一件不容易的事情。爲了實現RPC,首先得基於不同的操作系統提供的網絡模型實現網絡通信,然後需要自己封裝協議來實現RPC,通常爲了方便使用還結合使用Lua進行腳本調用。而golang語言原生支持RPC,極大地提高了開發效率。

·
·
·

• net/rpc包

在golang中,標準庫提供的net/rpc包實現了RPC協議的相關細節,開發者可以方便地使用該包編寫出RPC服務端和客戶端程序,這使得用golang開發多個進程之間通信變得非常簡單。

官網介紹:rpc包提供了基於網絡或其他I/O連接來訪問某個對象的導出函數的方法。服務端需要註冊提供RPC服務的對象,並以該對象類型的名稱作爲可見的服務名。對象註冊完成之後,該對象的導出函數將可以被遠程訪問。服務端可以註冊多個不同類型的對象作爲服務,但是需要注意的是,註冊同一類型的多個對象將引發錯誤。
·
·
·

導出函數需滿足的條件

• 函數的類型需要導出。
• 函數需要導出。
• 函數必須擁有兩個參數,參數必須是導出類型或內建類型。
• 函數的第二個參數必須是一個指針。
• 函數必須返回一個error類型的值。

滿足上述條件的函數可以簡單表示成:
在這裏插入圖片描述

• 類型T、T1和T2默認使用golang內置的encoding/gob包進行編碼解碼。
• 第一個參數argType表示由RPC客戶端傳入的參數。
• 第二個參數replyType表示要返回給RPC客戶端的結果。
• 函數最後返回一個error類型的值。如果一個error值返回,replyType參數將不會發送給RPC客戶端,而error值將會作爲一個字符串發送給RPC客戶端。

·
·
·

下面給出一個實例並且分析各個的作用

服務端代碼:

packagemain
 
import(
"errors"
"log"
"net"
"net/http"
"net/rpc"
"time"
)
 
typeArgsstruct{
A,Bint
}
 
typeQuotientstruct{
Quo,Remint
}
 
typeArithint
 
func(t*Arith)Multiply(args*Args,reply*int)error{
*reply=args.A*args.B
returnnil
}
 
func(t*Arith)Divide(args*Args,quo*Quotient)error{
ifargs.B==0{
returnerrors.New("dividebyzero")
}
 
quo.Quo=args.A/args.B
quo.Rem=args.A%args.B
returnnil
}
 
funcmain(){
arith:=new(Arith)
rpc.Register(arith)
rpc.HandleHTTP()
 
l,e:=net.Listen("tcp",":1234")
deferl.Close()
 
ife!=nil{
log.Fatal("listenerror:",e)
return
}
 
gohttp.Serve(l,nil)
log.Println("rpcserverstarted!")
 
for{
time.Sleep(1*time.Second)
}
}

客戶端代碼:

packagemain
 
import(
"log"
"net/rpc"
)
 
typeArgsstruct{
A,Bint
}
 
typeQuotientstruct{
Quo,Remint
}
 
funcmain(){
client,err:=rpc.DialHTTP("tcp","127.0.0.1:1234")
deferclient.Close()
 
iferr!=nil{
log.Fatal("dialingerror:",err)
return
}
 
args1:=&Args{2,3}
args2:=&Args{7,2}
args3:=&Args{7,0}
 
reply1:=0
reply2:=Quotient{}
reply3:=Quotient{}
 
err=client.Call("Arith.Multiply",args1,&reply1)
iferr!=nil{
log.Fatal("Aritherror:",err)
return
 
}
log.Println(reply1)//6
 
err=client.Call("Arith.Divide",args2,&reply2)
iferr!=nil{
log.Fatal("Aritherror:",err)
return
 
}
log.Println(reply2)//{31}
 
err=client.Call("Arith.Divide",args3,&reply3)
iferr!=nil{
log.Fatal("Aritherror:",err)//aritherror:dividebyzero
return
 
}
log.Println(reply3)
}
 

測試結果: 在這裏插入圖片描述
如上圖所示,再客戶端中成功將傳遞給服務端的參數按照服務端的方法計算出了結果。
·
·
·

下面開始分析各個步驟的具體作用

服務端
在這裏插入圖片描述
圖中所指示的是rpc必要的包

在這裏插入圖片描述
如中兩個定義的結構體是因爲實驗需要而定義的,當然也可以是其他形式的,這個的(1)是客戶端用來向服務端傳遞數據的,(2)是服務端將計算後的結果返回給客戶端的。

在這裏插入圖片描述
自己重新定義一個
在這裏插入圖片描述

如中的(1)就是客戶端傳遞進來的參數,(2)就是服務端將要返回給客戶端的參數
如果是剛剛開始學golang這裏介紹一下這個方法:
方法相對於函數:函數稱之爲函數在go裏面,我的理解是隻能夠通過直接調用,而方法區別於函數,只能通過特定的對象“應該是這麼稱之爲把,還是稱之爲結構體把”引用才能實現。實例如下:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
就如上圖所示的之後方法纔可以通過指定的結構體引用,而且在傳遞值的類型必須選用指針類型。
在這裏插入圖片描述
客戶端:
在這裏插入圖片描述
在這裏插入圖片描述
如果學過python網絡編程的可以類比一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章