这是gRPC教程的最后一部分/现在我们来编写我们的主服务器和客户端。
主服务器和客户端
创建两个独立的文件夹--服务器和客户端。每一个都将有自己的main.go文件。
另外,让我们创建我们的Makefile。
gen:
protoc --proto_path=proto proto/*.proto --go_out=plugins=grpc:pb --grpc-gateway_out=:pb --openapiv2_out=:swagger
clean:
rm pb/*.go
server1:
go run ~/server/main.go -port 50051
server2:
go run ~/server/main.go -port 50052
server1-tls:
go run ~/server/main.go -port 50051 -tls
server2-tls:
go run ~/server/main.go -port 50052 -tls
server:
go run ~/server/main.go -port 8080
server-tls:
go run ~/server/main.go -port 8080 -tls
rest:
go run ~/server/main.go -port 8081 -type rest -endpoint 0.0.0.0:8080
client:
go run ~/client/main.go -address 0.0.0.0:8080
client-tls:
go run ~/client/main.go -address 0.0.0.0:8080 -tls
test:
go test -cover -race ./...
cert:
cd cert; ./gen.sh; cd ..
.PHONY: gen clean server client test cert
打开server/main.go文件。
func main() {
port := flag.Int("port", 0, "server port")
flag.Parse()
log.Printf("start server on port %d", *port)
laptopStore := service.NewInMemoryLaptopStore()
laptopServer := service.NewLaptopServer(laptopStore)
pb.RegisterLaptopServiceServer(grpcServer, laptopServer)
address := fmt.Sprintf("0.0.0.0:%d", *port)
listener, err := net.Listen("tcp", address)
if err != nil {
log.Fatal("cannot start server: ", err)
}
err = grpcServer.Serve(listener)
if err != nil {
log.Fatal("cannot start server: ", err)
}
}
我们用之前的端口建立一个地址字符串,然后监听这个服务器地址进行TCP连接。我们需要一个服务器的端口,所以我使用 flag.Int() 函数从命令行参数中得到它。
最后,调用 grpcServer.Serve() 被调用来启动服务器。只要写一个致命的日志,如果发生任何错误就退出。这就是一个服务器的代码。
接下来,我们进行客户端的工作。
func main() {
serverAddress := flag.String("address", "", "the server address")
flag.Parse()
log.Printf("dial server %s", *serverAddress)
conn, err := grpc.Dial(*serverAddress, grpc.WithInsecure())
if err != nil {
log.Fatal("cannot dial server: ", err)
}
laptopClient := pb.NewLaptopServiceClient(conn)
laptop := sample.NewLaptop()
req := &pb.CreateLaptopRequest{
Laptop: laptop,
}
// set timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
res, err := laptopClient.CreateLaptop(ctx, req)
if err != nil {
st, ok := status.FromError(err)
if ok && st.Code() == codes.AlreadyExists {
// not a big deal
log.Print("laptop already exists")
} else {
log.Fatal("cannot create laptop: ", err)
}
return
}
log.Printf("created laptop with id: %s", res.Id)
}
我们用输入的地址调用grpc.Dial()函数,并创建一个连接。
如果发生错误,我们写一个致命的日志并退出。否则,我们用该连接创建一个新的笔记本客户端对象。
然后,我们生成一个新的笔记本,制作一个新的请求对象,然后用请求和上下文调用laptopClient.Createlaptop() 函数。这里我们使用context.WithTimeout() ,将这个请求的超时设置为5秒。
如果错误不是nil,我们把它转换成一个状态对象。如果状态代码是'AlreadyExists',那么我们就写一个正常的日志,否则就是致命的日志。
如果一切正常,我们就简单地写一个日志,说笔记本是用这个ID创建的。这就是客户端的情况。
我们的教程到此结束。