Skip to content

Go 服务端与客户端开发 ​

本章详细介绍如何使用 Go 语言开发 gRPC 服务端和客户端。

一、服务端开发 ​

1. 实现服务接口 ​

服务端需要实现 protobuf 定义的服务接口:

go
package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "your_project_path/proto"
)

// server 实现 GreeterServer 接口
type server struct {
    pb.UnimplementedGreeterServer
}

// SayHello 实现 RPC 方法
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf("收到请求: %s", in.GetName())
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

注意:必须嵌入 UnimplementedGreeterServer,保证向前兼容性。

2. 启动服务 ​

go
func main() {
    // 监听端口
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("监听失败: %v", err)
    }

    // 创建 gRPC 服务
    s := grpc.NewServer()
    
    // 注册服务
    pb.RegisterGreeterServer(s, &server{})

    log.Println("服务启动,监听 :50051")
    if err := s.Serve(lis); err != nil {
        log.Fatalf("服务启动失败: %v", err)
    }
}

3. 优雅关闭 ​

go
// 接收终止信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit

log.Println("正在关闭服务...")
s.GracefulStop()
log.Println("服务已关闭")

4. 服务端选项 ​

go
s := grpc.NewServer(
    grpc.MaxRecvMsgSize(1024*1024*10),    // 最大接收 10MB
    grpc.MaxSendMsgSize(1024*1024*10),    // 最大发送 10MB
    grpc.ConnectionTimeout(30*time.Second), // 连接超时
)

二、客户端开发 ​

1. 建立连接 ​

go
conn, err := grpc.Dial("localhost:50051",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithBlock(),  // 阻塞等待连接建立
)
if err != nil {
    log.Fatalf("连接失败: %v", err)
}
defer conn.Close()

2. 调用服务 ​

go
client := pb.NewGreeterClient(conn)

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "World"})
if err != nil {
    log.Fatalf("调用失败: %v", err)
}

log.Printf("收到响应: %s", resp.GetMessage())

3. Context 超时控制 ​

go
// 设置 5 秒超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "World"})

4. 客户端选项 ​

go
conn, err := grpc.Dial("localhost:50051",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithKeepaliveParams(keepalive.ClientParameters{
        Time:    10 * time.Second, // 每 10 秒发送心跳
        Timeout: 3 * time.Second,  // 心跳超时
    }),
)

三、完整示例 ​

完整的可运行代码请参考实战项目:

四、最佳实践 ​

  1. 错误处理:始终检查 error,使用 status.Error() 返回 gRPC 错误码
  2. 连接管理:客户端连接可复用,不要每次调用都新建连接
  3. 超时设置:为每个 RPC 调用设置合理的超时时间
  4. 优雅关闭:服务端使用 GracefulStop() 确保处理完已有请求
  5. 并发安全:服务实现必须保证并发安全