使用Golang的单项gRPC 教程

228 阅读2分钟

这是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创建的。这就是客户端的情况。

我们的教程到此结束。