目录结构
go.mod
module grpc_demo
go 1.16
require (
github.com/golang/protobuf v1.5.2 // indirect
google.golang.org/grpc v1.39.0
google.golang.org/protobuf v1.26.0
)
hello.proto
生成代码命令:protoc -I . stream.proto --go_out=plugins=grpc:.
proto完整代码:
syntax = "proto3";
// 引入第三方的proto
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
option go_package = "../proto";
service Greeter{
rpc Ping(google.protobuf.Empty) returns (Pong);
}
// 枚举类型
enum Gender{
MALE = 0;
FEMALE = 1;
}
message Pong{
string name = 1; // 姓名
int32 age = 2; // 年龄
Gender gender = 3; // 性别
map<string, string> skill = 4; // 技能
google.protobuf.Timestamp birthDay = 5;// 生日
}
server.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc/metadata"
"grpc_demo/zdp09_time_message/proto"
"net"
"time"
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/timestamppb"
)
const PORT = ":50052"
type Server struct {
}
func (s *Server) Ping(ctx context.Context, request *empty.Empty) (*proto.Pong, error) {
//接收metadata
md, ok := metadata.FromIncomingContext(ctx)
if ok {
fmt.Println("get metadata")
// 从metadata中提取内容
if nameSlice, ok := md["name"]; ok {
// 是一个slice
fmt.Println("nameSlice: ", nameSlice)
// 从slice中提取内容
for name, err := range nameSlice {
fmt.Println(name, err)
}
}
}
// 返回内容
return &proto.Pong{
Name: "张大鹏",
Age: 22,
Gender: proto.Gender_MALE, // 使用枚举类型
Skill: map[string]string{
"Java": "80%",
"Python": "95%",
"Go": "90%",
},
BirthDay: timestamppb.New(time.Now()),
}, nil
}
func main() {
// 监听端口
lis, err := net.Listen("tcp", PORT)
if err != nil {
panic(err)
}
// 创建grpc服务
s := grpc.NewServer()
// 注册grpc服务
proto.RegisterGreeterServer(s, &Server{})
// 启动grpc服务
err = s.Serve(lis)
if err != nil {
panic(err)
}
}
client.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc/metadata"
"grpc_demo/zdp09_time_message/proto"
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial("localhost:50052", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
// 创建metadata
md := metadata.New(map[string]string{
"name": "zhangdapeng",
"password": "zhangdapeng",
})
// 将metadata写入context上下文
ctx := metadata.NewOutgoingContext(context.Background(), md)
// ping:携带metadata
pingResponse, err := c.Ping(ctx, &empty.Empty{})
if err != nil {
panic(err)
}
fmt.Println(pingResponse.Name, pingResponse.Age, pingResponse.Gender, pingResponse.Skill, pingResponse.BirthDay)
}
运行测试
服务端控制台输出
客户端控制台输出