本文是对 gRPC-go 英文文档做的中文翻译说明,对原文进行了适当删减并且加入了自己的理解,原文链接为 https://grpc.io/docs/languages/go/
- gRPC-go 快速开始
- gRPC 简介
- gRPC 核心概念、架构和生命周期
- gRPC-go 基础教程
一、gRPC-go 快速开始
1.先决条件:
协议编译器的Go插件:
执行下述指令安装Go的协议编译器插件:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
2.运行示例代码:
1.拉取代码仓库
git clone -b v1.71.0 --depth 1 https://github.com/grpc/grpc-go
2.进入文件所在路径
cd grpc-go/examples/helloworld
3.编译并执行服务端代码
go run greeter_server/main.go
4.开启另一个终端,编译并执行客户端代码查看输出
go run greeter_client/main.go

3.更新 gRPC 服务
接下来重写一个新的服务。gRPC服务是使用协议缓冲区( protobuf )定义的。在服务器和客户端存根都有一个 SayHello() RPC方法,该方法从客户端获取 HelloRequest 参数,并从服务器返回 HelloReply ,该方法在 protobuf 的定义如下,打开 helloworld.proto 文件可见如下内容:
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
在 helloworld.proto 添加一个新的 SayHelloGain() 方法,该方法具有相同的请求和响应类型:
syntax = "proto3";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Sends another greeting
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
4.重新生成 gRPC 代码
在使用新的服务方法之前,需要重新编译更新的 .proto 文件。在 examples/helloworld 目录中运行以下命令:
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
helloworld/helloworld.proto
这将重新生成 helloworld/helloworld.pb.go 和 helloworld_grpc.pb.go 文件。
5.在服务端和客户端实现方法
已经重新生成了服务器和客户端代码,但仍需要在应用程序中手动实现并调用新方法。
(1)更新服务端
打开 greeter_server/main.go ,并向其中添加以下功能:
// 在服务端实现 SayHelloAgain 方法
func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello again" + in.GetName()}, nil
}
(2)更新客户端
打开 greeter_client/main.go ,将以下代码添加到main()函数体的末尾:
// 在客户端运行 SayHelloAgain 方法
r, err = c.SayHelloAgain(ctx, &pb.HelloRequest{Name: *name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
(3)执行
执行服务端程序
go run greeter_server/main.go
执行客户端程序,并且添加一个名称作为命令行参数
go run greeter_client/main.go --name=Alice
输出结果如下:

至此,快速启动一个 gRPC 代码示例已完成,接下来我们详细研究研究整个代码的内容
6.解析 helloworld.proto 文件
helloworld.proto 文件是一个 protobuf 定义文件,用于定义 gRPC 服务和消息格式。
syntax = "proto3";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Sends another greeting
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
(1)语法版本声明
syntax = "proto3";
表示指定使用的是 Protocol Buffers 第 3 版语法
(2)代码生成选项
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
- go_package :指定生成的 Go 代码的导入路径
- Java 相关选项 java_multiple_files:生成多个 Java 文件(而不是单个大文件);java_package:生成的 Java 代码的包名;java_outer_classname:外层类名
(3)包声明
package helloworld;
定义 protobuf 的包名,防止命名冲突
(4)服务定义
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Sends another greeting
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}
- 定义一个名为 Greeter 的 gRPC 服务
- 包含两个 RPC 方法:SayHello:发送问候,接收 HelloRequest,返回 HelloReply;SayHelloAgain:发送另一种问候,参数和返回类型相同
(5)消息类型定义
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
- 定义客户端发送给服务器的请求格式 HelloRequest ,包含一个字符串字段 name (赋值为 1 代表字段编号为 1),用于传递用户的名字
- 定义服务器返回给客户端的响应格式 HelloReply ,包含一个字符串字段 message(赋值为 1 代表字段编号为 1),用于返回问候语
7.解析 helloworld.pb.go 文件
helloworld.pb.go 文件是由 protoc-gen-go 工具根据 helloworld.proto 文件自动生成的 Go 代码,用于实现 protobuf 的序列化和反序列化功能。
(1)包和导入
package helloworld
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
- 包名与 proto 文件中定义的 package helloworld 一致
- 导入的包主要用于 protobuf 的反射和运行时支持
(2)消息类型定义
HelloRequest 结构体
type HelloRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
- 对应 proto 文件中的 HelloRequest 消息
- 包含一个 Name 字符串字段
- 内部字段:state:消息状态;sizeCache:缓存消息大小;unknowFields:存储未知字段
HelloRequest 结构体方法
func (x *HelloRequest) Reset() {
*x = HelloRequest{}
mi := &file_helloworld_helloworld_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HelloRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HelloRequest) ProtoMessage() {}
func (x *HelloRequest) ProtoReflect() protoreflect.Message {
mi := &file_helloworld_helloworld_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
func (x *HelloRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
- 提供标准的 protobuf 消息接口
- 包含字段访问器和序列化支持方法
- Reset():重置消息状态;String():返回消息的字符串表示;ProtoMessage():标记为 protobuf 消息;ProtoReflect():返回反射接口;GetName():获取 Name 字段值。
HelloReply 结构体
type HelloReply struct {
state protoimpl.MessageState `protogen:"open.v1"`
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
- 类似 HelloRequest,对应 proto 文件中的 HelloReply 消息,以及一些自动生成的方法
- 包含一个 Message 字符串字段
8.解析 helloworld_grpc.pb.go 文件
helloworld_grpc.pb.go 文件是由 protoc-gen-go-grpc 工具根据 helloworld.proto 文件自动生成的 gRPC 服务接口代码,为 Go 语言提供了客户端和服务端的实现框架。
(1)包和导入
package helloworld
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
- 包名与 proto 文件中定义的 package helloworld 一致
- 导入的包主要用于 gRPC 通信和上下文处理
(2)方法全名常量
const (
Greeter_SayHello_FullMethodName = “/helloworld.Greeter/SayHello”
Greeter_SayHelloAgain_FullMethodName = “/helloworld.Greeter/SayHelloAgain”
)
- 定义 gRPC 方法的完整路径名
- 格式为 /<package>.<service>/<method>
- 用于 gRPC 调用时标识具体方法
(3)客户端接口和实现
客户端接口
type GreeterClient interface {
// Sends a greeting
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
// Sends another greeting
SayHelloAgain(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}
- 定义客户端可以调用的方法
- 每个方法都有上下文、请求参数和可选的调用选项
- 返回响应和可能的错误
客户端实现
type greeterClient struct {
cc grpc.ClientConnInterface
}
func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
return &greeterClient{cc}
}
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(HelloReply)
err := c.cc.Invoke(ctx, Greeter_SayHello_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *greeterClient) SayHelloAgain(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(HelloReply)
err := c.cc.Invoke(ctx, Greeter_SayHelloAgain_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
- greeterClient 是接口的具体实现
- 通过 NewGreeterClient 方法创建并返回 GreeterClient 接口实现类对象 greeterClient
- 通过 greeterClient 可以调用远程方法 SayHello 和 SayHelloAgain
- 在方法内部 Invoke 方法执行实际的 RPC 调用
- 自动处理请求的序列化和响应的反序列化
(4)服务端接口和实现
服务端接口
type GreeterServer interface {
// Sends a greeting
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
// Sends another greeting
SayHelloAgain(context.Context, *HelloRequest) (*HelloReply, error)
mustEmbedUnimplementedGreeterServer()
}
- 定义服务端需要实现的方法
- 包含强制嵌入 mustEmbedUnimplementedGreeterServer 的要求
未实现的服务端
type UnimplementedGreeterServer struct{}
func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
}
func (UnimplementedGreeterServer) SayHelloAgain(context.Context, *HelloRequest) (*HelloReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SayHelloAgain not implemented")
}
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
func (UnimplementedGreeterServer) testEmbeddedByValue() {}
- 为向前兼容提供的默认实现
- 所有方法返回 “未实现” 错误
- 服务实现应嵌入此结构体
服务注册
func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
// If the following call pancis, it indicates UnimplementedGreeterServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Greeter_ServiceDesc, srv)
}
- 将服务实现注册到 gRPC 服务器
- 使用自动生成的服务描述符
服务描述符和处理函数
var Greeter_ServiceDesc = grpc.ServiceDesc{
ServiceName: "helloworld.Greeter",
HandlerType: (*GreeterServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SayHello",
Handler: _Greeter_SayHello_Handler,
},
{
MethodName: "SayHelloAgain",
Handler: _Greeter_SayHelloAgain_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "helloworld/helloworld.proto",
}
- 包含服务的完整描述信息
- 定义方法名和对应的处理函数
- 用于 gRPC 服务器路由请求到正确的处理程序
处理函数实现
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HelloRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GreeterServer).SayHello(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Greeter_SayHello_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Greeter_SayHelloAgain_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HelloRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GreeterServer).SayHelloAgain(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Greeter_SayHelloAgain_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GreeterServer).SayHelloAgain(ctx, req.(*HelloRequest))
}
return interceptor(ctx, in, info, handler)
}
- 实际处理 gRPC 请求的函数
- 负责解码请求、调用服务方法和编码响应
- 支持拦截器机制
总结下来:helloworld_grpc.pb.go 文件提供了:客户端可以调用的 gRPC 服务的接口和实现;服务端实现的 gRPC 服务的框架;服务注册和路由机制;请求/响应的编解码处理;拦截器支持。对于开发者需要:使用 NewGreeterClient 方法创建客户端;实现 GreeterServer 接口提供业务逻辑;调用 RegisterGreeterServer 注册服务。
9.解析 greeter_server/main.go 服务端文件
该文件是一个完整的 gRPC 服务端实现,基于 helloworld.proto 的 protobuf 协议服务接口实现。
(1)包声明和导入
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
var (
port = flag.Int("port", 50051, "The server port")
)
- package main 表示这是一个可执行程序
- 导入的包包括:标准库:context, flag, fmt, log, net;gRPC 核心库:google.golang.org/grpc;生成的 protobuf 代码:pb 是别名
(2)命令行参数
var (
port = flag.Int("port", 50051, "The server port")
)
- 定义了一个命令行参数 port,默认值 50051
- 用户可以通过 -port=8080 来指定服务端口
(3)服务实现结构体
type server struct {
pb.UnimplementedGreeterServer
}
- server 结构体实现了 gRPC 服务接口
- 内嵌 UnimplementedGreeterServer 确保向前兼容
- 这是 protobuf 生成代码中定义的基础结构
(4)服务实现方法
func (s *server) SayHello(_ context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
实现 SayHello RPC 方法
参数:
- context.Context:请求上下文(这里用 _ 忽略)
- *pb.HelloRequest:客户都安请求,包含 name 字段
返回值:
- *pb.HelloReply:响应消息,包含问候语
- error:错误信息(nil 表示成功)
功能:记录日志并返回 “Hello {name}”
(5)主函数
func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
- flag.Parse():解析命令行参数
- net.Listen:在指定端口创建 TCP 监听器,格式为”:50051″ 表示监听所有接口的 50051 端口
- grpc.NewServer():创建新的 gRPC 服务器实例
- RegisterGreeterServer:注册我们的服务实现
- s.Serve(lis):启动服务,开始监听请求,这是一个阻塞调用,会一直运行直到出错或停止
整体的代码执行流程如下:
- 启动程序,解析端口参数(默认 50051)
- 创建 TCP 监听器
- 创建 gRPC 服务器实例
- 注册服务实现
- 启动服务并开始监听客户端请求
- 当客户端调用时:接收请求并解码;调用对应的服务方法(SayHello 或 SayHelloAgain);编码响应并返回给客户端
要使用这个服务,客户端可以通过 gRPC 协议连接到指定端口,调用 SayHello 或 SayHelloAgain 方法,传递名字并接收问候语响应。
10.解析 greeter_client/main.go 客户端文件
该文件是一个完整的 gRPC 客户端实现,用于调用之前定义的 Greeter 服务。
(1)包声明和导入
package main
import (
"context"
"flag"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
- package main 表示这是一个可执行程序
- 导入的包包括:标准库:context, flag, log, time;gRPC 核心库:google.golang.org/grpc;不安全凭证(用于测试):google.golang.org/grpc/credentials/insecure;生成的 protobuf 代码:pb 是别名
(2)常量和命令行参数
const (
defaultName = "world"
)
var (
addr = flag.String("addr", "localhost:50051", "the address to connect to")
name = flag.String("name", defaultName, "Name to greet")
)
- defaultName:默认的问候名称(”world”)
- 命令行参数:addr :服务端地址,默认 localhost:50051;name :要问候的名字,默认 “world”
(3)主函数实现
func main() {
flag.Parse()
// Set up a connection to the server.
conn, err := grpc.NewClient(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
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.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
// 运行 SayHelloAgain 方法
r, err = c.SayHelloAgain(ctx, &pb.HelloRequest{Name: *name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
- flag.Parse():解析命令行参数
- grpc.NewClient:创建 gRPC 客户端连接
- defer conn.Close():确保程序退出前关闭连接
- c := pb.NewGreeterClient(conn):使用连接创建 Greeter 服务客户端,NewGreeterClient 是 protobuf 生成的函数
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel() 创建带超时(1秒)的上下文 - 调用 SayHello 方法,传递 HelloRequest 包含名字参数
- 处理响应和错误
二、gRPC 简介
本章节着重介绍 gRPC 和 protobuf。gRPC 可以使用 protobuf 作为其接口定义语言(IDL)和底层消息交换格式。
在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序上的方法,就像它是本地对象一样,让开发者更容易创建分布式应用程序和服务。与许多 RPC 系统一样,gRPC 基于定义服务的思想,指定可以通过参数和返回类型远程调用的方法。在服务器端,服务器实现此接口并运行 gRPC 服务器来处理客户端调用。在客户端,客户端有一个存根(在某些语言中仅称为客户端),它提供与服务器相同的方法。

gRPC 客户端和服务器可以在各种环境中运行并相互通信,从谷歌内部的服务器到开发者自己的桌面,并且可以用 gRPC 支持的任何语言编写。例如,开发者可以用 Java 创建一个 gRPC 服务器,并使用Go、Python 或 Ruby 的客户端。
默认情况下,gRPC 使用 Protocol Buffers,这是谷歌成熟的开源机制,用于序列化结构化数据(尽管它也可以与 JSON 等其他数据格式一起使用)。以下是对其工作原理的简要介绍。
使用 protocol buffers 的第一步是定义要在 proto 文件中序列化的数据的结构:这是一个扩展名为 .proto 的普通文本文件。协议缓冲区数据被结构化为消息,其中每条消息都是一个小的逻辑信息记录,包含一系列称为字段的名称-值对。这里有一个简单的例子:
message Person {
string name = 1;
int32 id = 2;
bool has_ponycopter = 3;
}
然后,一旦指定了数据结构,就可以使用协议缓冲区编译器协议从原型定义中生成首选语言的数据访问类。这些为每个字段提供了简单的访问器,如 GetName 方法,以及将整个结构序列化/解析到原始字节的方法。因此,例如,如果您选择的语言是 C++,在上面的示例上运行编译器将生成一个名为 Person 的类。然后,您可以在应用程序中使用此类来填充、序列化和检索Person协议缓冲区消息。
开发者可以在普通原型文件中定义 gRPC 服务,RPC 方法参数和返回类型指定为协议缓冲区消息:
// The greeter service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
gRPC 使用 protocol 和一个特殊的 gRPC 插件从原型文件生成代码:开发者将获得生成的 gRPC 客户端和服务器代码,以及用于填充、序列化和检索消息类型的常规协议缓冲区代码。

No responses yet