GRPC-Gateway

https://github.com/grpc-ecosystem/grpc-gateway
https://gitee.com/go-ecosystem/grpc-gateway.git
https://gitee.com/tkxiong/grpc-go.git

install

git clone 
https://gitee.com/go-ecosystem/grpc-gateway.git
cd grpc-gateway/protoc-gen-grpc-gatewqy
go build
cp protoc-gen-grpc-gateway /bin
cd ../cd protoc-gen-openapiv2/
go build
cp protoc-gen-openapiv2 /bin
git clone https://github.com/grpc/grpc-go.git
cd grpc-go/cmd/protoc-gen-go-grpc
go build
cp protoc-gen-go-grpc /bin

编译

拷贝$GOMODCACHE/github.com/grpc-ecosystem/grpc-gateway@v1.16.0/third_party/googleapis/google 到项目proto目录下

syntax="proto3";
option go_package="../pb";

import "google/api/annotations.proto";

message ReqMsg{
	string value=1;
}
message ResMsg{
	string value=1;
}
message FileBinary{
	bytes data = 1;
}
service TripService{
	rpc Echo(ReqMsg) returns (ResMsg){
		option (google.api.http)={
			post : "/v1/pb/echo"
			body : "*"
		};
	}
	//获取数据流
	rpc DownFile (ReqMsg) returns (stream FileBinary){
		option (google.api.http)={
			post : "/v1/pb/getfile"
			body : "*"
		};
	}
}
protoc --go_out=plugins=grpc:./ trip.proto
protoc --grpc-gateway_out=logtostderr=true:./ trip.proto   //trip.pb.gw.go

//生成trip.pb.go和trip_grpc.pb.go
protoc -I ./ --go_out ../pb --go_opt paths=source_relative  --go-grpc_out ../pb --go-grpc_opt paths=source_relative  trip.proto
//trip.pb.gw.go
protoc -I . --grpc-gateway_out ../pb --grpc-gateway_opt logtostderr=true --grpc-gateway_opt paths=source_relative --grpc-gateway_opt generate_unbound_methods=true trip.proto

build.sh

#!/bin/bash

#生成普通的pb文件 /trip.pb.go和trip_grpc.pb.go
protoc -I ./ --go_out ../pb --go_opt paths=source_relative  --go-grpc_out ../pb --go-grpc_opt paths=source_relative  $1

#生成反向代理的pb网关文件 trip.pb.gw.go
protoc -I . --grpc-gateway_out ../pb --grpc-gateway_opt logtostderr=true --grpc-gateway_opt paths=source_relative --grpc-gateway_opt generate_unbound_methods=true $1

build.sh trip.proto

server.go

package main

import (
	"context"
	"log"
	"net"

	"grpcStream/grpcGateway/pb"

	"google.golang.org/grpc"
)

const (
	port = ":8088"
)

type server struct {
	pb.UnimplementedTripServiceServer
}

func (s *server) Echo(ctx context.Context, req *pb.ReqMsg) (*pb.ResMsg, error) {
	return &pb.ResMsg{Value: req.GetValue()}, nil
}
func (s *server) DownFile(req *pb.ReqMsg, rep pb.TripService_DownFileServer) error {
	if req.Value == "" {
		return errors.New("input params empty")
	}
	fileBuffer, err := ioutil.ReadFile(req.Value)
	if err != nil {
		return err
	}
	/*数据过大会报错
	err = rep.Send(&pb.FileBinary{Data: fileBuffer})
	if err != nil {
		log.Println("err:", err.Error())
	} */
	//循环发送
	byteOnce := 50 //每次发送50字节
	index := 0     //第几次发送
	cnt := 0       //总发送数据量
	for {
		//如果最后一次发送大于最大长度,认为最后一次发送
		if index*byteOnce+byteOnce >= len(fileBuffer) {
			if err := rep.Send(&pb.FileBinary{
				Data: fileBuffer[index*byteOnce:],
			}); err != nil {
				log.Panicln("send failed:", err.Error())
				return err
			}
			cnt += len(fileBuffer) - index*byteOnce
			break
		} else {
			//正常的每次50个字节
			if err := rep.Send(&pb.FileBinary{
				Data: fileBuffer[index*byteOnce : index*byteOnce+byteOnce],
			}); err != nil {
				log.Panicln("send failed:", err.Error())
				return err
			}
			cnt += byteOnce
		}
	}
	log.Panicln("send bytes len:", cnt)
	return nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v\n", err)
	}

	s := grpc.NewServer()
	pb.RegisterTripServiceServer(s, &server{})

	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

client.go

package main

import (
	"context"
	"log"
	"time"

	"grpcStream/grpcGateway/pb"

	"google.golang.org/grpc"
)

const (
	addr = "localhost:8088"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	conn, err := grpc.DialContext(ctx, addr, grpc.WithBlock(), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v\n", err)
	}
	defer conn.Close()
	// c := pb.NewEchoServiceClient(conn)
	c := pb.NewTripServiceClient(conn)

	log.Printf("echo request: wang\n")

	r, err := c.Echo(ctx, &pb.ReqMsg{Value: "wang"})
	if err != nil {
		log.Fatalf("could not echo: %v\n", err)
	}

	log.Printf("Echo reply: %s\n", r.GetValue())
}

httpserver.go

package main

import (
	"context"
	"flag"
	"net/http"

	gw "grpcStream/grpcGateway/pb"

	"github.com/golang/glog"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"google.golang.org/grpc"
)

var (
	grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:8088", "gRPC server endpoint")
)

func run() error {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}
	err := gw.RegisterTripServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
	if err != nil {
		return err
	}

	return http.ListenAndServe(":8081", mux)
}

func main() {
	flag.Parse()
	defer glog.Flush()

	if err := run(); err != nil {
		glog.Fatal(err)
	}
}

curl -XPOST --data '{"value":"wangzhilei"}' http://192.168.11.140:18081/v1/pb/echo
{"value":"wangzhilei"}

获取数据流

[root@localhost gRPCStream]# curl -XPOST --data '{"value":"server.go"}' http://192.168.11.140:18081/v1/pb/getfile
{"result":{"data":"LyoKICogQERlc2NyaXB0dGlvbjoKICogQHZlcnNpb246CiAqIEBBdXRob3I6IHdhbmd6aGlsZWkKICogQERhdGU6IDIwMjEtMDktMTUgMTY6MDc6NTUKICogQExhc3RFZGl0b3JzOiB3YW5nemhpbGVpCiAqIEBMYXN0RWRpdFRpbWU6IDIwMjEtMDktMTYgMDk6MjY6NDUKICovCnBhY2thZ2UgbWFpbgoKaW1wb3J0ICgKCSJjb250ZXh0IgoJImVycm9ycyIKCSJmbXQiCgkiaW8vaW91dGlsIgoJImxvZyIKCSJuZXQiCgoJImdycGNTdHJlYW0vZ3JwY0dhdGV3YXkvcGIiCgoJImdvb2dsZS5nb2xhbmcub3JnL2dycGMiCikKCmNvbnN0ICgKCXBvcnQgPSAiOjgwODgiCikKCnR5cGUgc2VydmVyIHN0cnVjdCB7CglwYi5VbmltcGxlbWVudGVkVHJpcFNlcnZpY2VTZXJ2ZXIKfQoKZnVuYyAocyAqc2VydmVyKSBFY2hvKGN0eCBjb250ZXh0LkNvbnRleHQsIHJlcSAqcGIuUmVxTXNnKSAoKnBiLlJlc01zZywgZXJyb3IpIHsKCWZtdC5QcmludGxuKCJyZXE6IiwgcmVxLkdldFZhbHVlKCkpCglyZXR1cm4gJnBiLlJlc01zZ3tWYWx1ZTogcmVxLkdldFZhbHVlKCl9LCBuaWwKfQpmdW5jIChzICpzZXJ2ZXIpIERvd25GaWxlKHJlcSAqcGIuUmVxTXNnLCByZXAgcGIuVHJpcFNlcnZpY2VfRG93bkZpbGVTZXJ2ZXIpIGVycm9yIHsKCWlmIHJlcS5WYWx1ZSA9PSAiIiB7CgkJcmV0dXJuIGVycm9ycy5OZXcoImlucHV0IHBhcmFtcyBlbXB0eSIpCgl9CglmaWxlQnVmZmVyLCBlcnIgOj0gaW91dGlsLlJlYWRGaWxlKHJlcS5WYWx1ZSkKCWlmIGVyciAhPSBuaWwgewoJCXJldHVybiBlcnIKCX0KCWVyciA9IHJlcC5TZW5kKCZwYi5GaWxlQmluYXJ5e0RhdGE6IGZpbGVCdWZmZXJ9KQoJaWYgZXJyICE9IG5pbCB7CgkJbG9nLlByaW50bG4oImVycjoiLCBlcnIuRXJyb3IoKSkKCX0KCXJldHVybiBlcnIKfQoKZnVuYyBtYWluKCkgewoJbGlzLCBlcnIgOj0gbmV0Lkxpc3RlbigidGNwIiwgcG9ydCkKCWlmIGVyciAhPSBuaWwgewoJCWxvZy5GYXRhbGYoImZhaWxlZCB0byBsaXN0ZW46ICV2XG4iLCBlcnIpCgl9CgoJcyA6PSBncnBjLk5ld1NlcnZlcigpCglwYi5SZWdpc3RlclRyaXBTZXJ2aWNlU2VydmVyKHMsICZzZXJ2ZXJ7fSkKCglpZiBlcnIgOj0gcy5TZXJ2ZShsaXMpOyBlcnIgIT0gbmlsIHsKCQlsb2cuRmF0YWxmKCJmYWlsZWQgdG8gc2VydmU6ICV2IiwgZXJyKQoJfQp9Cg=="}}

解码
[root@localhost gRPCStream]# echo "LyoKICogQERlc2NyaXB0dGlvbjoKICogQHZlcnNpb246CiAqIEBBdXRob3I6IHdhbmd6aGlsZWkKICogQERhdGU6IDIwMjEtMDktMTUgMTY6MDc6NTUKICogQExhc3RFZGl0b3JzOiB3YW5nemhpbGVpCiAqIEBMYXN0RWRpdFRpbWU6IDIwMjEtMDktMTYgMDk6MjY6NDUKICovCnBhY2thZ2UgbWFpbgoKaW1wb3J0ICgKCSJjb250ZXh0IgoJImVycm9ycyIKCSJmbXQiCgkiaW8vaW91dGlsIgoJImxvZyIKCSJuZXQiCgoJImdycGNTdHJlYW0vZ3JwY0dhdGV3YXkvcGIiCgoJImdvb2dsZS5nb2xhbmcub3JnL2dycGMiCikKCmNvbnN0ICgKCXBvcnQgPSAiOjgwODgiCikKCnR5cGUgc2VydmVyIHN0cnVjdCB7CglwYi5VbmltcGxlbWVudGVkVHJpcFNlcnZpY2VTZXJ2ZXIKfQoKZnVuYyAocyAqc2VydmVyKSBFY2hvKGN0eCBjb250ZXh0LkNvbnRleHQsIHJlcSAqcGIuUmVxTXNnKSAoKnBiLlJlc01zZywgZXJyb3IpIHsKCWZtdC5QcmludGxuKCJyZXE6IiwgcmVxLkdldFZhbHVlKCkpCglyZXR1cm4gJnBiLlJlc01zZ3tWYWx1ZTogcmVxLkdldFZhbHVlKCl9LCBuaWwKfQpmdW5jIChzICpzZXJ2ZXIpIERvd25GaWxlKHJlcSAqcGIuUmVxTXNnLCByZXAgcGIuVHJpcFNlcnZpY2VfRG93bkZpbGVTZXJ2ZXIpIGVycm9yIHsKCWlmIHJlcS5WYWx1ZSA9PSAiIiB7CgkJcmV0dXJuIGVycm9ycy5OZXcoImlucHV0IHBhcmFtcyBlbXB0eSIpCgl9CglmaWxlQnVmZmVyLCBlcnIgOj0gaW91dGlsLlJlYWRGaWxlKHJlcS5WYWx1ZSkKCWlmIGVyciAhPSBuaWwgewoJCXJldHVybiBlcnIKCX0KCWVyciA9IHJlcC5TZW5kKCZwYi5GaWxlQmluYXJ5e0RhdGE6IGZpbGVCdWZmZXJ9KQoJaWYgZXJyICE9IG5pbCB7CgkJbG9nLlByaW50bG4oImVycjoiLCBlcnIuRXJyb3IoKSkKCX0KCXJldHVybiBlcnIKfQoKZnVuYyBtYWluKCkgewoJbGlzLCBlcnIgOj0gbmV0Lkxpc3RlbigidGNwIiwgcG9ydCkKCWlmIGVyciAhPSBuaWwgewoJCWxvZy5GYXRhbGYoImZhaWxlZCB0byBsaXN0ZW46ICV2XG4iLCBlcnIpCgl9CgoJcyA6PSBncnBjLk5ld1NlcnZlcigpCglwYi5SZWdpc3RlclRyaXBTZXJ2aWNlU2VydmVyKHMsICZzZXJ2ZXJ7fSkKCglpZiBlcnIgOj0gcy5TZXJ2ZShsaXMpOyBlcnIgIT0gbmlsIHsKCQlsb2cuRmF0YWxmKCJmYWlsZWQgdG8gc2VydmU6ICV2IiwgZXJyKQoJfQp9Cg==" | base64 -d

yaml

type: google.api.Service
config_version: 3

http:
  rules:
  - selector: pb.TripService.GetTrip
    get: /trip/{id}
protoc --grpc-gateway_out=paths=source_relative,grpc_api_configuration=trip.yaml:./ trip.proto
posted @ 2021-09-14 17:26  wangzhilei  阅读(651)  评论(0)    收藏  举报