安裝protoc
- 打開地址https://github.com/protocolbuffers/protobuf/releases,根據自身系統找到對應的版本,比如我是win64,則下載 protoc-3.11.2-win64.zip 。
- 解壓縮到 C:\protoc-3.11.2-win64。
- 加入到系統環境變量。
安裝 protoc-gen-go
- 拉取代碼go get -u github.com/golang/protobuf/protoc-gen-go,如果能找到protoc-gen-go.exe,則把可執行文件直接複製到 C:\protoc-3.11.2-win64 。
- 如果無法找到protoc-gen-go.exe,則可以在下面的目錄執行 go build,會生成一個新的protoc-gen-go.exe,同上把可執行文件直接複製到 C:\protoc-3.11.2-win64 。
測試
測試結構
編寫helloword.proto
syntax = "proto3";
package hello;
service MyRpc {
rpc SayHello (HelloRequest) returns (HelloReply) {
}
}
message firstWrap {
string name = 1;
string age = 2;
secondWrap home = 3;
}
message secondWrap {
string addr = 1;
string num = 2;
}
message HelloRequest {
firstWrap info = 1;
}
message HelloReply {
string message = 1;
}
解釋:
- syntax 定義proto的版本。
- package 定義生成的*.pb.go所在的包。
- service MyRpc 定義了這個 GRPC 的服務名字和裏面包含的 SayHello 方法。
- firstWrap 和 secondWrap 類似於定義了2個消息體,並且 firstWrap 嵌入了 secondWrap 。
- MyRpcRequest 和 MyRpcResponse 定義了請求參數和返回參數的消息體。
生成 helloword.pb.go
進入目錄rpct/hello,執行 protoc --go_out=plugins=grpc:. *.proto 會生成 helloword.pb.go。
編寫RPC server
// 業務實現方法的容器
type rpcContainer struct{}
func (r *rpcContainer) SayHello(ctx context.Context, req *pb.MyRpcRequest) (*pb.MyRpcResponse, error) {
resData := fmt.Sprintf("hello %s %s", req.GetInfo().GetName(), req.GetInfo().GetHome().GetNum())
return &pb.MyRpcResponse{Message: resData}, nil
}
func main() {
//監聽端口
lis, err := net.Listen("tcp", ":12222")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
//註冊rpc
ser := grpc.NewServer()
pb.RegisterMyRpcServer(ser, &rpcContainer{})
//運行
if err := ser.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
編寫RPC client
func main() {
// 連接rpc服務器
conn, err := grpc.Dial(":12222", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
client := pb.NewMyRpcClient(conn)
defer conn.Close()
//請求數據
data := &pb.MyRpcRequest{
Info: &pb.FirstWrap{
Name: "zhexiao",
Age: "yoyo",
Home: &pb.SecondWrap{
Addr: "my address",
Num: "my number",
},
},
}
//發送連接數據
res, err := client.SayHello(context.Background(), data)
if err != nil {
log.Fatalf("could not send data: %v", err)
}
//打印返回的數據
fmt.Println(res.Message)
}