1. 简单 RPC 模式
一元 RPC
模式也被称为简单 RPC
模式。在该模式中,当客户端调用服务器端的远程方法时,客户端发送请求至服务器端并获得一个响应,与响应一起发送的还有状态细节以及元数据。这种模式下,客户端发送一个请求后,必须等待服务器发回响应才能继续发送下一个请求。
如图所示,客户端发送一个带有订单 ID
的请求,服务器端给出响应,响应中包含订单的信息。因此,它遵循一元 RPC
模式。
2. 目录结构
$ tree
.
├── bin # 可执行文件目录
│ ├── client
│ └── server
├── client # 客户端代码文件
│ └── client.go
├── go.mod
├── go.sum
├── pb # proto 和生成代码命令
│ ├── run.sh
│ ├── string.pb.go
│ └── string.proto
├── server # 服务端代码
│ └── server.go
└── service # 服务端具体实现代码
└── service.go
5 directories, 10 files
$
3. proto 定义
string.proto
内容:
syntax = "proto3";
package pb;
option go_package = "./;pb";
service StringService{
rpc Concat(StringRequest) returns (StringResponse) {}
}
message StringRequest {
string A = 1;
string B = 2;
}
message StringResponse {
string Ret = 1;
string err = 2;
}
生成代码命令
#!/bin/bash
protoc -I=./ --go_out=plugins=grpc:. ./string.proto
4. 服务端实现
service.go
内容:
package service
import (
"context"
"errors"
"io"
"log"
"strings"
"time"
stream_pb "rpcDemo/pb"
)
const (
StrMaxSize = 1024
)
// Service errors
var (
ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
ErrStrValue = errors.New("maximum size of 1024 bytes exceeded")
)
type StringService struct{}
// Context 包含一些用于控制 gRPC 行为的构造,比如截止时间和取消功能。
func (s *StringService) Concat(ctx context.Context, req *stream_pb.StringRequest) (*stream_pb.StringResponse, error) {
if len(req.A)+len(req.B) > StrMaxSize {
response := stream_pb.StringResponse{Ret: ""}
return &response, nil
}
response := stream_pb.StringResponse{Ret: req.A + req.B}
return &response, nil
}
server.go
内容
package main
import (
"flag"
"log"
"rpcDemo/pb"
"rpcDemo/service"
"net"
"google.golang.org/grpc"
)
func main() {
flag.Parse()
lis, err := net.Listen("tcp", "127.0.0.1:1234")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
stringService := new(service.StringService)
pb.RegisterStringServiceServer(grpcServer, stringService)
grpcServer.Serve(lis)
}
5. 客户端实现
client.go
内容
package main
import (
"context"
"fmt"
"io"
"log"
"strconv"
stream_pb "rpcDemo/pb"
"google.golang.org/grpc"
)
func main() {
serviceAddress := "127.0.0.1:1234"
conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure())
if err != nil {
panic("connect error")
}
defer conn.Close()
simpleRPC(conn)
}
func simpleRPC(conn *grpc.ClientConn) {
bookClient := stream_pb.NewStringServiceClient(conn)
stringReq := &stream_pb.StringRequest{A: "A", B: "B"}
reply, _ := bookClient.Concat(context.Background(), stringReq)
fmt.Printf("StringService Concat : %s concat %s = %s\n", stringReq.A, stringReq.B, reply.Ret)
}
6. 编译运行
编译运行服务端
$ go build -o ./bin/server ./server/
$ ./bin/server
编译运行客户端
$ go build -o ./bin/client ./client/
$ ./bin/client