go windows + grpc 以及grpc流模式使用

国内网络问题,windows使用grpc过程

安装protoc

将写好的proto文件,生成pb.go文件,下载地址https://github.com/protocolbuffers/protobuf/releases,下载下来的是一个zip文件,将文件解压找到/bin/protoc.exe,将其配置到环境变量。在控制台中输入protoc --version,打印出下载protoc版本说明安装正确。

go windows + grpc 以及grpc流模式使用

安装grpc

这里因为网络问题,需要从github上拉源码安装,

git clone https://github.com/golang/net.git %GOPATH%/src/golang.org/x/net
git clone https://github.com/golang/text.git %GOPATH%/src/golang.org/x/text
git clone https://github.com/grpc/grpc-go.git %GOPATH%/src/google.golang.org/grpc
git clone https://github.com/protocolbuffers/protobuf-go.git %GOPATH%/src/google.golang.org/protobuf
git clone https://github.com/google/go-genproto.git %GOPATH%/src/google.golang.org/genproto

这里是grpc依赖的,已经编译时依赖的全部资源

安装protoc-gen-go

go get github.com/golang/protobuf/protoc-gen-go

我这里使用的是protoc-gen-gofast(有大佬做过测试,go-fast要快4-7倍,https://studygolang.com/articles/22824

使用源码安装 

git clone https://github.com/gogo/protobuf.git
go install protoc-gen-gofast

至此准备工作已经完成,接下来进行简单的测试

Grpc测试

grpc基于http2.0,再次同时记录一下grpc流模式的使用(http2.0 :1. 多路复用  2.TCP连接  3.二进制代替文本 4.标题压缩 5.服务器推送,grpc也同样具有这些功能)

proto文件

syntax = "proto3";

package proto;
option go_package = "proto";

message HelloReq {
  string name = 1;
  string content = 2;
}

message HelloResp{
  string content = 1;
}

message HelloListResp{
  repeated string content = 1;
}

service HelloService {
  // 普通调用
  rpc Hello(HelloReq) returns (HelloResp){}
  // 客户端流模式
  rpc HelloClientStream(stream HelloReq) returns (HelloListResp){}
  // 服务端流模式
  rpc HelloServerStream(HelloReq) returns (stream HelloResp){}
  // 双向流模式
  rpc HelloStream(stream HelloReq) returns (stream HelloResp){}
}

在proto文件的目录下执行 protoc --gofast_out=plugins=grpc:. *.proto 生成 hello.pb.go 文件。

服务端代码:

package main

import (
	"context"
	"demo/proto"
	"fmt"
	"google.golang.org/grpc"
	"io"
	"net"
)

type HelloServer struct {
}

func (*HelloServer) Hello(ctx context.Context, in *proto.HelloReq) (*proto.HelloResp, error) {
	return &proto.HelloResp{
		Content: fmt.Sprintf("%v : %v", in.GetName(), in.GetContent()),
	}, nil
}

func (*HelloServer) HelloClientStream(stream proto.HelloService_HelloClientStreamServer) error {
	var users []string
	for {
		recv, err := stream.Recv()
		//接收完了返回结果并关闭
		if err == io.EOF {
			return stream.SendAndClose(&proto.HelloListResp{
				Content: users,
			})
		}
		if err != nil {
			return err
		}
		users = append(users, fmt.Sprintf(recv.GetName()+" : "+recv.GetContent()))
	}
}

func (*HelloServer) HelloServerStream(in *proto.HelloReq, stream proto.HelloService_HelloServerStreamServer) error {
	for i := 0; i < 10; i++ {
		stream.Send(&proto.HelloResp{
			Content: fmt.Sprintf("%v - %v : %v", i, in.GetName(), in.GetContent()),
		})
	}
	return nil
}

func (*HelloServer) HelloStream(stream proto.HelloService_HelloStreamServer) error {
	for {
		recv, err := stream.Recv()
		//接收完了返回
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		err = stream.Send(&proto.HelloResp{
			Content: fmt.Sprintf("%v : %v", recv.GetName(), recv.GetContent()),
		})
		if err != nil {
			return err
		}
	}
}

func main() {
	listen, err := net.Listen("tcp", ":8001")
	if err != nil {
		panic(err)
	}
	s := grpc.NewServer()
	proto.RegisterHelloServiceServer(s, &HelloServer{})
	err = s.Serve(listen)
	if err != nil {
		panic(err)
	}
}

客户端实现:

package main

import (
	"context"
	"demo/proto"
	"fmt"
	"google.golang.org/grpc"
	"io"
	"strconv"
	"time"
)

func main() {
	conn, err := grpc.Dial("localhost:8001", grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	cli := proto.NewHelloServiceClient(conn)

	// 普通调用
	hello, err := cli.Hello(context.Background(), &proto.HelloReq{
		Name:    "demo",
		Content: "Hello World",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(hello.GetContent())

	// 客户端流模式测试
	client, err := cli.HelloClientStream(context.Background())
	if err != nil {
		panic(err)
	}
	for i := 0; i < 5; i++ {
		client.Send(&proto.HelloReq{
			Name:    "world" + strconv.Itoa(i),
			Content: "hello",
		})
	}
	client.CloseSend()
	recv, err := client.CloseAndRecv()
	if err != nil {
		panic(err)
	}
	for i := range recv.Content {
		fmt.Println(recv.GetContent()[i])
	}

	// 服务端流模式测试
	stream, err := cli.HelloServerStream(context.Background(), &proto.HelloReq{
		Name:    "hello",
		Content: "world",
	})
	for {
		resp, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				panic(err)
			}
		}
		fmt.Println(resp.Content)
	}

	// 双向流模式测试
	helloStream, err := cli.HelloStream(context.Background())
	if err != nil {
		panic(err)
	}

	go func() {
		for {
			resp, err := helloStream.Recv()
			if err != nil {
				if err == io.EOF {
					break
				} else {
					panic(err)
				}
			}
			fmt.Println(resp.Content)
		}
	}()

	for i := 0; i < 5; i++ {
		time.Sleep(time.Second)
		fmt.Println("send", i)
		helloStream.Send(&proto.HelloReq{
			Name:    "hello" + strconv.Itoa(i),
			Content: "world",
		})
	}
	helloStream.CloseSend()
	time.Sleep(time.Second)
}

目录结构如下:

go windows + grpc 以及grpc流模式使用

上一篇:JavaScript-原型链


下一篇:Day9