1. 程式人生 > >編寫基於gRPC的C/S通訊模型

編寫基於gRPC的C/S通訊模型

1、編寫.proto檔案

包含:
1)定義service,用service{}包起來
service ServiceName{
    rpc funcname1(Request) returns (Reponse){}
    rpc funcname2(Request) returns (Reponse){}
}
2)message Request{}
3)message Response{}

2、編譯生成golang對應的rpc程式碼

命令:protoc --go_out=plugins=grpc:{go程式碼的輸出路徑,生成的.pb.go檔案所在目錄} xxx.proto在生成的.pb.go檔案中,包含如下內容:
//有關請求、應答的struct
type Request struct{} //請求struct
type Response struct{} //應答struct

//service的客戶端的API,客戶端會呼叫funcname1和funcname2
type ServiceNameClient interface{
    funcname1(三個引數)
    funcname2(三個引數)
}
type serviceNameClient struct{}
func NewServiceNameClient() ServiceNameClient{} //建立客戶端
func (c *serviceNameClient) funcname1(三個引數)(*Response, error)
func (c *serviceNameClient) funcname2(三個引數)(*Response, error)

//service的伺服器的API,伺服器會呼叫funcname1和funcname2
type ServiceNameServer interface{
    funcname1(兩個引數)
    funcname2(兩個引數)
}
注意:伺服器並沒有對應的struct,也沒有實現兩個函式,所以需要在伺服器的main.go中建立server struct,並實現該介面的這兩個函式,即server的method

//使用pb包呼叫註冊已實現的rpc介面類server
func RegisterServiceNameServer(){
    s.RegisterService()
}

3、編寫客戶端

//定義目的埠??、伺服器地址
const(
    address = "127.0.0.1:50051"
    defaultname = "strings"
)

//主函式
func main(){
    //發起連線
    conn, err := grpc.Dial(address, grpc.WithInsecure())
   
     if err != nil{} //錯誤處理
   
     defer conn.Close() //防止記憶體洩漏
   
     //建立客戶端
    c := 包名.NewServiceNameClient(conn) //包名就是剛剛編譯生成的.pb.go中的package,因為呼叫的函式就是.pb.go中的,所以package是.pb.go中的package
    
    name := defaultName
     if len(os.Args) > 1 { name = os.Args[1] }

    //發起請求
    r, err := c.funcname1()//發起請求,返回響應
    log.Printf("%s", r.Message)//列印響應的內容
}

4、編寫伺服器端

const (
    port = ":50051"//宣告監聽埠
)

//主函式
func main(){
    lis, err := net.Listen("tcp", port) //監聽指定埠,使用tcp協議
    if err != nil{}
    
     type server struct{} //server用來實現包名.ServiceNameServer,這是個介面,介面中的函式就是funcname1和funcname2,和Client對應的struct的內建函式是一樣的,只不過client的程式碼通過直接編譯就生成了,但是server的內建函式,需要在main函式中實現。所以在main函式中需要定義server struct,然後實現兩個附屬於server struct的內建函式,即實現ServerNameServer介面。
    //需要實現.pb.go中的ServerNameServer介面
    func (s *server) funcname1(兩個引數){}
    func (s *servre) funcname2(兩個引數){}

    //生成一個rpc伺服器
    s := grpc.NewServer()

    //註冊已實現的rpc介面類server
    包名.RegisterServiceNameServer(s, &server{})

    //在grpc伺服器上註冊反射service
    reflection.Register(s)
    if err := s.Serve(lis); err != nil {
          log.Fatalf("%v", err)
     }
}