一、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)
}
}