目录结构:
├── client.go
├── helloworld
│ ├── build.sh
│ ├── helloworld.pb.go
│ └── helloworld.proto
└── server.go
proto 定义
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (Helloreq) returns (Hellorsp) {}
}
message Helloreq {
string message = 1;
}
message Hellorsp {
string message = 1;
}
构建
protoc -I . --go_out=plugins=grpc:. ./helloworld.proto
sever.go
package main
import (
"context"
"log"
"net"
pb "./helloworld"
"google.golang.org/grpc"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.Helloreq) (*pb.Hellorsp, error) {
log.Printf("Received: %v", in.GetMessage())
return &pb.Hellorsp{Message: "Hello " + in.GetMessage()}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
client.go
package main
import (
"context"
"log"
"os"
"time"
pb "./helloworld"
"google.golang.org/grpc"
)
const (
address = "localhost:50051"
defaultName = "world"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
message := defaultName
if len(os.Args) > 1 {
message = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.Helloreq{Message: message})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
go run server.go
go run client.go
参考一个不错的例子: https://zhuanlan.zhihu.com/p/30624616
gRPC 中的三种类型的 RPC 方法。
-
simple RPC
应用于常见的典型的 Request/Response 模型。客户端通过 stub 请求 RPC 的服务端并等待服务端的响应。
-
Server-side streaming RPC
客户端给服务端发送一个请求并获取服务端返回的流,用以读取一连串的服务端响应。stream 关键字在响应类型的前面。// 例子
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){}
-
Client-side streaming RPC
客户端发送的请求 payload 有一连串的的信息,通过流给服务端发送请求。stream 关键字在请求类型前面。 // 例子
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {}
-
Bidirectional streaming RPC
服务端和客户端之间都使用 read-write stream 进行通信。stream 关键字在请求类型和响应类型前面。// 例子
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){}
如果有多个服务的话,可以在proto文件中,声明在一起:
// The Customer sercie definition
service Customer {
rpc GetCustomers(GetCustomersRequest) returns (GetCustomersResponse) {}
rpc CreateCustomer (CustomerRequest) returns (CustomerResponse) {}
}
声明为数组:
message GetCustomersResponse {
int32 ret = 1;
message keyword {
string word = 1;
}
// 声明为数组
repeated keyword wordarray = 3;
}
在代码里面可以这样写入rsp:
func (s *server) GetCustomers(ctx context.Context, in *pb.GetCustomersRequest) (*pb.GetCustomersResponse, error) {
log.Printf("GetCustomers")
return &pb.GetCustomersResponse{
Ret: 1,
Wordarray: []*pb.GetCustomersResponseKeyword{
&pb.GetCustomersResponseKeyword{
Word: "hello",
},
&pb.GetCustomersResponseKeyword{
Word: "golang",
},
&pb.GetCustomersResponseKeyword{
Word: "grpc",
},
},
}, nil
}