go语言grpc的快速体验-grpc流模式

server.go

package main

import (
	"awesomeProject123/grpc_test/proto"
	"context"
	"google.golang.org/grpc"
	"net"
)

type Server struct {
	*proto.UnimplementedGreeterServer
}

func (s *Server) mustEmbedUnimplementedGreeterServer() {
	//TODO implement me
	panic("implement me")
}

// SayHello ctx context.Context协程
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
	return &proto.HelloReply{
		Message: "hello" + request.Name,
	}, nil
}

func main() {
	//new服务
	grpc1 := grpc.NewServer()

	//注册
	proto.RegisterGreeterServer(grpc1, &Server{})
	//监听
	listen, err := net.Listen("tcp", "0.0.0.0:8080")
	if err != nil {
		panic("failed  to listen:" + err.Error())
	}

	//启动 不会关闭
	err = grpc1.Serve(listen)
	if err != nil {
		panic("failed  to start:" + err.Error())
	}
}

client.go

package main

import (
	"awesomeProject123/grpc_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
)

func main() {
	//建立服务器连接
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())

	if err != nil {
		panic(err)
	}

	defer conn.Close()

	//调用protobuf的函数穿件客户单
	client := proto.NewGreeterClient(conn)

	//调用sayHello
	sayHello, err := client.SayHello(context.Background(), &proto.HelloRequest{
		Name: "bobby",
	})
	if err != nil {
		return
	}

	fmt.Println(sayHello.Message)
}
https://blog.csdn.net/zhanglifan_cd/article/details/125925511?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169994824316800185875269%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=169994824316800185875269&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-125925511-null-null.142^v96^control&utm_term=%E6%97%A0%E6%B3%95%E5%B0%86%20%26Server%7B%7D%20%28%E7%B1%BB%E5%9E%8B%20*Server%29%20%E7%94%A8%E4%BD%9C%E7%B1%BB%E5%9E%8B%20GreeterServer%20%E7%B1%BB%E5%9E%8B%E6%97%A0%E6%B3%95%E5%AE%9E%E7%8E%B0%20GreeterServer%EF%BC%8C%E5%9B%A0%E4%B8%BA%E7%B1%BB%E5%9E%8B%E6%9C%89%E6%9C%AA%E5%AF%BC%E5%87%BA%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%98%AF%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E4%B8%AD%E5%AE%9A%E4%B9%89&spm=1018.2226.3001.4187

grpc流模式

  1. Unary RPC - 也叫做 Simple RPC 简单的请求-响应,一问一答式的RPC请求,类似本地方法调用
  2. Server-side streaming RPC - 服务端流RPC模式,服务端在接收到客户请求后主动推送数据。应用场景:APP消息推送、股票动态数据
  3. Client-side streaming RPC -客户端流RPC模式,在该模式下客户端会发送多次请求,服务端则会发送最终响应给客户端。需要注意的是服务端并不一定要等到从客户端接收所有消息后,才发送响应。基于此,可以在接收到流中的一条或者几条消息之后就发送响应。也可以在等到所有消息后再发送响应。
  4. Bidirectional streaming RPC -全双工流RPC模式,即数据在客户端、服务端双向流动。但是发起方必须是客户端。感觉可以使用这种方式进行IM聊天,哈哈。

proto

syntax = "proto3";

option go_package=".;proto";

service Greeter{
  //服务端流模式
  rpc GetStream(StreamReqData) returns(stream StreamResData);

  //客户端流模式
  rpc PostStream(stream StreamReqData) returns(StreamResData);

  //双向流模式
  rpc AllStream(stream StreamReqData) returns(stream StreamResData);
}

message StreamReqData{
  string data = 1;
}

message StreamResData{
  string data = 1;
}

protoc --go_out=. --go-grpc_out=. .\stream.proto

client.go

package main

import (
	"awesomeProject123/stream_grpc_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"sync"
	"time"
)

func main() {
	//初始化连接
	conn, err := grpc.Dial("localhost:50052", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}

	defer conn.Close()

	//服务端模式
	/*client := proto.NewGreeterClient(conn)

	res, _ := client.GetStream(context.Background(), &proto.StreamReqData{
		Data: "大家一起学习加我qq921190764",
	})

	for {
		recv, err := res.Recv()
		if err != nil {
			fmt.Println(err)
			break
		}
		fmt.Println(recv.Data)
	}*/

	//客户端流模式
	/*
		client := proto.NewGreeterClient(conn)

		putS, _ := client.PostStream(context.Background())

		i := 0
		//rpc error: code = Canceled desc = context canceled
		for {
			i++
			_ = putS.Send(&proto.StreamReqData{
				Data: fmt.Sprintf("921190764大家一起学习%d", i),
			})
			time.Sleep(time.Second)

			if i > 10 {
				break
			}
		}
	*/

	//双向流
	client := proto.NewGreeterClient(conn)

	allStream, _ := client.AllStream(context.Background())

	group := sync.WaitGroup{}
	group.Add(2)
	go func() {
		defer group.Done()
		for {
			data, _ := allStream.Recv()
			fmt.Println("收到客户端消息: " + data.Data)
		}
	}()

	go func() {
		defer group.Done()
		for {
			_ = allStream.Send(&proto.StreamReqData{Data: "我是客户端"})
			time.Sleep(time.Second)
		}
	}()

	group.Wait()
}

server.go

package main

import (
	"awesomeProject123/stream_grpc_test/proto"
	"fmt"
	"google.golang.org/grpc"
	"net"
	"sync"
	"time"
)

const PORT = ":50052"

type server struct {
	*proto.UnimplementedGreeterServer
}

// GetStream 只不过在调用我们重写的 rpc 方法
// 服务端流模式
func (s *server) GetStream(data *proto.StreamReqData, streamServer proto.Greeter_GetStreamServer) error {
	i := 0
	for {
		i++
		_ = streamServer.Send(&proto.StreamResData{
			Data: fmt.Sprintf("%v", time.Now().Unix()) + data.Data,
		})
		time.Sleep(time.Second)
		if i > 10 {
			break
		}
	}
	return nil
}

// PostStream 客户端流模式
func (s *server) PostStream(streamServer proto.Greeter_PostStreamServer) error {
	for {
		recv, err := streamServer.Recv()
		if err != nil {
			fmt.Println(err)
			break
		}
		fmt.Println(recv.Data)
	}

	return nil
}

// AllStream 双向流模式
func (s *server) AllStream(streamServer proto.Greeter_AllStreamServer) error {

	//用于等待一组线程的结束。父线程调用Add方法来设定应等待的线程的数量。
	//每个被等待的线程在结束时应调用Done方法。同时,主线程里可以调用Wait方法阻塞至所有线程结束。
	group := sync.WaitGroup{}
	group.Add(2)
	go func() {
		defer group.Done()
		for {
			data, _ := streamServer.Recv()
			fmt.Println("收到客户端消息: " + data.Data)
		}
	}()

	go func() {
		defer group.Done()
		for {
			_ = streamServer.Send(&proto.StreamResData{Data: "我是服务器"})
			time.Sleep(time.Second)
		}
	}()

	group.Wait()
	return nil
}

func (s *server) mustEmbedUnimplementedGreeterServer() {
	//TODO implement me
	panic("implement me")
}

func main() {
	listen, err := net.Listen("tcp", PORT)
	if err != nil {
		panic(err)
	}

	newServer := grpc.NewServer()

	proto.RegisterGreeterServer(newServer, &server{})

	err = newServer.Serve(listen)
	if err != nil {
		return
	}
}

你可能感兴趣的:(golang,开发语言,后端)