gRPC学习笔记

一、gPRC普通模式和流模式

客户端:

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"io"
	"log"
	"tesql/go_advance/proto"
	"time"
)

func main() {
	//与gRPC服务建立连接
	conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	//基于已建立的连接构造对象,返回的client是HelloServiceClient接口对象
	client := proto.NewHelloServiceClient(conn)
	//通过HelloServiceClient接口定义的方法就可以调用服务端对应的gRPC服务提供的方法
	reply, err := client.Hello(context.Background(), &proto.String{Value: "hello"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(reply.GetValue())

	//>>>gRPC流
	stream, err := client.Channel(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	//向服务端发送数据
	go func() {
		for {
			if err := stream.Send(&proto.String{Value: "2022"}); err != nil {
				log.Fatal(err)
			}
			time.Sleep(time.Second)
		}
	}()
	//接收服务端返回的数据
	for {
		reply, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		}
		fmt.Println(reply.GetValue())
	}
}

服务端:

package main

import (
	"context"
	"google.golang.org/grpc"
	"io"
	"log"
	"net"
	"tesql/go_advance/proto"
)

type HelloServiceImpl struct{}

func (p *HelloServiceImpl) Hello(ctx context.Context, args *proto.String) (*proto.String, error) {
	reply := &proto.String{Value: "hello:" + args.GetValue()}
	return reply, nil
}
//gRPC流
func (p *HelloServiceImpl) Channel(stream proto.HelloService_ChannelServer) error {
	for {
		args, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				return nil
			}
			return err
		}

		reply := &proto.String{Value: "hello:" + args.GetValue()}

		err = stream.Send(reply)
		if err != nil {
			return err
		}
	}
}
func main() {
	//构造gRPC服务
	grpcServer := grpc.NewServer()
	//注册我们实现的服务
	proto.RegisterHelloServiceServer(grpcServer, new(HelloServiceImpl))
	//在一个监听端口上提供gRPC服务
	lis, err := net.Listen("tcp", ":1234")
	if err != nil {
		log.Fatal(err)
	}
	grpcServer.Serve(lis)
}

proto文件:

syntax = "proto3";

package main;

option go_package = "go_advance/proto";

message String {
    string value = 1;
}
service HelloService {
    rpc Hello (String) returns (String);

    //stream指定启用流特性,参数接收客户端参数的流,返回值是返回给客户端的流
    rpc Channel (stream String) returns (stream String);
}

service PubsubService {
    //普通RPC方法
    rpc Publish (String) returns (String);
    //单向的流服务
    rpc Subscribe (String) returns (stream String);
}

生成pb.go文件的命令:

//go_advance/proto/hello.proto指proto文件的位置,并且在同一目录下生成pb.go文件
protoc --go_out=plugins=grpc:. go_advance/proto/hello.proto

二、发布订阅

服务端:

package main

import (
	"context"
	"github.com/docker/docker/pkg/pubsub"
	"google.golang.org/grpc"
	"log"
	"net"
	"strings"
	"tesql/go_advance/proto"
	"time"
)

type PubsubService struct {
	pub *pubsub.Publisher
}

func NewPubsubService() *PubsubService {
	return &PubsubService{
		pub: pubsub.NewPublisher(100*time.Millisecond, 10),
	}
}

func (p *PubsubService) Publish(ctx context.Context, arg *proto.String) (*proto.String, error) {
	p.pub.Publish(arg.GetValue())
	return &proto.String{}, nil
}

func (p *PubsubService) Subscribe(arg *proto.String, stream proto.PubsubService_SubscribeServer) error {
	ch := p.pub.SubscribeTopic(func(v interface{}) bool {
		if key, ok := v.(string); ok {
			if strings.HasPrefix(key,arg.GetValue()) {
				return true
			}
		}
		return false
	})

	for v := range ch {
		if err := stream.Send(&proto.String{Value: v.(string)}); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	//构造gRPC服务
	grpcServer := grpc.NewServer()
	//注册我们实现的服务
	proto.RegisterPubsubServiceServer(grpcServer, NewPubsubService())
	//在一个监听端口上提供gRPC服务
	lis, err := net.Listen("tcp", ":4321")
	if err != nil {
		log.Fatal(err)
	}
	grpcServer.Serve(lis)
}

客户端(订阅):

package main


import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"io"
	"log"
	"tesql/go_advance/proto"
)

func main() {
	conn, err := grpc.Dial("localhost:4321", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	client := proto.NewPubsubServiceClient(conn)
	stream, err := client.Subscribe(
		context.Background(), &proto.String{Value: "golang:"},
	)
	if err != nil {
		log.Fatal(err)
	}

	for {
		reply, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		}

		fmt.Println(reply.GetValue())
	}
}

客户端(发布):

package main

import (
	"context"
	"google.golang.org/grpc"
	"log"
	"tesql/go_advance/proto"
)

func main() {
	//grpc.WithInsecure()跳过对服务器证书的验证
	conn, err := grpc.Dial("localhost:4321", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	client := proto.NewPubsubServiceClient(conn)

	_, err = client.Publish(
		context.Background(), &proto.String{Value: "golang: hello Go"},
	)
	if err != nil {
		log.Fatal(err)
	}
	_, err = client.Publish(
		context.Background(), &proto.String{Value: "docker: hello Docker"},
	)
	if err != nil {
		log.Fatal(err)
	}
}

你可能感兴趣的:(golang,grpc)