使用 protoc
指令產生出兩個檔案,這兩個檔案如何去實現Server端與Client端,當然也可以時作出Server端與Client使用不同的語言。
syntax = "proto3";
package NAME;
service ServiceName {
rpc RPCName (stream ReqData) returns (stream ResData){}
}
message ReqData {
string data = 1;
}
message ResData {
string data = 1;
}
Server 基本使用
產出的grpc.pb.go
中可以看到,需對於interface和struct要有一定的了解。
type ServiceNameServer interface {
RPCName(ServiceNameServer_RPCNameServer) error
mustEmbedUnimplementedServiceNameServer()
}
type UnimplementedServiceNameServer struct {
}
// ... 相關功能
type ServiceNameServer_RPCNameServer interface {
Send(*ResData) error
Recv() (*ReqData, error)
grpc.ServerStream
}
func (*UnimplementedServiceNameServer) RPCName(ServiceNameServer_RPCNameServer) error {
... // 系統自動生成功能
}
server/main.go
package main
import (
"go-grpc/pro"
"google.golang.org/grpc"
)
// PORT port號
const PORT = ":50051"
type server struct {
pro.UnimplementedServiceNameServer // 將 grpc.pb.go 的 struct 註冊過來
}
func (s *server) RPCName(allStr pro.ServiceNameServer_RPCNameServer) error {
// 處理 allStr.Recv() 和 處理 allStr.Send()
}
func main() {
// 監聽口
lis, err := net.Listen("tcp", PORT)
if err != nil {
return
}
// 建立一個 grpc 服務器
s := grpc.NewServer()
// 註冊事件
pro.RegisterServiceServer(s, &server{})
// 處理連結
s.Serve(lis)
}
Client 基本使用
產出的grpc.pb.go
中可以看到,需對於interface和struct要有一定的了解。
type ServiceNameClient interface {
RPCName(ctx context.Context, opts ...grpc.CallOption) (ServiceName_RPCNameClient, error)
}
type serviceNameClient struct {
cc grpc.ClientConnInterface
}
func (c *serviceNameClient) RPCName(ctx context.Context, opts ...grpc.CallOption) (ServiceName_RPCNameClient, error) {
// ... 系統自動生成
x := &serviceNameRPCNameClient{stream}
return x, nil
}
type ServiceName_RPCNameClient interface {
Send(*ReqData) error
Recv() (*ResData, error)
grpc.ClientStream
}
type serviceNameRPCNameClient struct {
grpc.ClientStream
}
client/main.go
package main
import (
"context"
"google.golang.org/grpc"
"go-grpc/pro"
_ "google.golang.org/grpc/balancer/grpclb"
)
const (
ADDRESS = "0.0.0.0:50051"
)
func main() {
//建立 gRPC連線
conn, err := grpc.Dial(ADDRESS, grpc.WithInsecure())
if err != nil {
return
}
defer conn.Close()
//建立一個client。
c := pro.NewServiceNameClient(conn)
allStr, err := c.RPCName(context.Background())
if err != nil {
fmt.Println(err)
}
go func() {
// data, err := allStr.Recv()
}()
go func() {
// allStr.Send()
}()
}