按照慣例,這裏從一個Hello項目開始,本項目定義了一個Hello Service,客戶端發送包含字符串名字的請求,服務端返回Hello消息。git
編寫.proto
描述文件github
編譯生成.pb.go
文件golang
服務端實現約定的接口並提供服務tcp
客戶端按照約定調用方法請求服務google
$GOPATH/src/grpc-go-practice/ example/ |—— hello/ |—— client/ |—— main.go // 客戶端 |—— server/ |—— main.go // 服務端 |—— proto/ |—— hello.proto // proto描述文件 |—— hello.pb.go // proto編譯後文件
syntax = "proto3"; // 指定proto版本 package proto; // 指定包名 // 定義Hello服務 service Hello { // 定義SayHello方法 rpc SayHello(HelloRequest) returns (HelloReply) {} } // HelloRequest 請求結構 message HelloRequest { string name = 1; } // HelloReply 響應結構 message HelloReply { string message = 1; }
hello.proto文件中定義了一個Hello Service,該服務包含一個SayHello
方法,同時聲明瞭HelloRequest
和HelloReply
消息結構用於請求和響應。客戶端使用HelloRequest
參數調用SayHello
方法請求服務端,服務端響應HelloReply
消息。protobuf的語法後面會詳細介紹,這裏先不用過多糾結。code
.pb.go
文件:# 編譯hello.proto protoc -I . --go_out=plugins=grpc:. ./hello.proto
生成的.pb.go
文件,按照.proto
文件中的說明,包含服務端接口HelloServer
描述,客戶端接口及實現HelloClient
,及HelloRequest
、HelloResponse
結構體,不要手動編輯該文件。server
package main import ( "net" pb "go-grpc-practice/example/proto" // 引入編譯生成的包 "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) const ( // Address gRPC服務地址 Address = "127.0.0.1:50052" ) // 定義helloService並實現約定的接口 type helloService struct{} // HelloService ... var HelloService = helloService{} func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { resp := new(pb.HelloReply) resp.Message = "Hello " + in.Name + "." return resp, nil } func main() { listen, err := net.Listen("tcp", Address) if err != nil { grpclog.Fatalf("failed to listen: %v", err) } // 實例化grpc Server s := grpc.NewServer() // 註冊HelloService pb.RegisterHelloServer(s, HelloService) grpclog.Println("Listen on " + Address) s.Serve(listen) }
運行:接口
go run main.go Listen on 50051 //服務端已開啓並監聽50051端口
服務端引入編譯後的proto
包,實現約定的接口,接口描述能夠查看hello.pb.go
文件中的HelloServer
接口描述。實例化grpc Server並註冊HelloService,開始提供服務。字符串
package main import ( pb "go-grpc-practice/example/proto" // 引入proto包 "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) const ( // Address gRPC服務地址 Address = "127.0.0.1:50052" ) func main() { // 鏈接 conn, err := grpc.Dial(Address, grpc.WithInsecure()) if err != nil { grpclog.Fatalln(err) } defer conn.Close() // 初始化客戶端 c := pb.NewHelloClient(conn) // 調用方法 reqBody := new(pb.HelloRequest) reqBody.Name = "gRPC" r, err := c.SayHello(context.Background(), reqBody) if err != nil { grpclog.Fatalln(err) } grpclog.Println(r.Message) }
運行:rpc
go run main.go Hello gRPC // 接收到服務端響應
客戶端初始化鏈接後直接調用聲明的方法,便可向服務端發起請求,使用姿式就像調用本地方法同樣。若是你收到了"Hello gRPC"的回覆,恭喜你已經會使用go-gRPC了。
下節將詳細介紹protobuf的語法,並詳細解析protobuf聲明與編譯後golang代碼的對應關係。