Go语言操作grpc详细使用

2023-05-16

Go语言操作grpc详细使用

  • 零、参考链接
  • 一、protobuf的详细使用
  • 二、grpc与protobuf的go文件的生成
    • 1.安装两个插件
    • 2.写proto文件
    • 3.编译proto文件,生成go文件
  • 三、grpc的详细使用
    • 1.一元RPC模式
    • 2.客户端流RPC模式
    • 3.服务器端流RPC模式
    • 4.双向流RPC模式

零、参考链接

视频:90分钟搞懂分布式RPC开源框架

一、protobuf的详细使用

protobuf的单独使用

二、grpc与protobuf的go文件的生成

1.安装两个插件

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

2.写proto文件

syntax = "proto3";

option go_package = "../proto_go;protos";


message Person{
  string name = 1;
  int32 id = 2;
}

message IPhoneInfo {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum phoneType{
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message phoneNumber{
    string number = 1;
    phoneType type = 2;
  }

  phoneNumber phones = 4;
}

service ProdService{    //grpc服务,这是最简单的一元grpc模式
  rpc GetProdStock(Person) returns (IPhoneInfo);
}

3.编译proto文件,生成go文件

在pbfiles的文件目录下,运行下面的命令

protoc --go_out=../proto_go --go_opt=paths=source_relative --go-grpc_out=../proto_go --go-grpc_opt=paths=source_relative echo.proto

会在proto_go下生成两个文件
1111

注意:每次修改了pbfiles中的.proto文件之后,都要重新编译生成两个文件

三、grpc的详细使用

可以直接看这个:gRPC开发: gRPC的四种通信模式

1.一元RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

service ProdService{
  rpc GetProdStock(Person) returns (IPhoneInfo);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"log"
	"time"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	c := protos.NewProdServiceClient(conn)

	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,  //无用瞎写的
		}
		ack, err := c.GetProdStock(context.Background(), p)
		if err != nil {
			panic(err)
		}
		fmt.Println(ack)
		time.Sleep(time.Second)
	}
//并发协程测试,也是没问题的
	var wg sync.WaitGroup
	wg.Add(len(person))
	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,
		}

		go func(*protos.Person) {
			ack, err := c.GetProdStock(context.Background(), p)
			if err != nil {
				panic(err)
			}
			fmt.Println(ack)
			wg.Done()
		}(p)

	}

	wg.Wait()
}

服务端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	protos "grpc/proto_go"
	"net"
)

type server struct {
	protos.UnimplementedProdServiceServer
	//或者在这里面添加你需要的字段
}

func (s *server) GetProdStock(ctx context.Context, req *protos.Person) (*protos.IPhoneInfo, error) {
	name := req.GetName()
	fmt.Println(name)
	if info, ok := AddressBook[name]; ok {
		return info, nil
	}
	return nil, status.Errorf(codes.NotFound, "Order does not exist.:", req.Name, req.Id)
}

var AddressBook map[string]*protos.IPhoneInfo

func main() {
	//0.创建db
	DBAddressBook()
	//1.创建rpcserver
	rpcs := grpc.NewServer()
	//2.将上一步创建的rpc服务器,和对应的服务,进行注册
	protos.RegisterProdServiceServer(rpcs, &server{})
	//3.创建一个监听服务
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}
	defer listen.Close()
	//4.启动rpc服务
	if err = rpcs.Serve(listen); err != nil {
		panic(err)
	}
}

func DBAddressBook() {
	AddressBook = make(map[string]*protos.IPhoneInfo)
	AddressBook["cjs"] = &protos.IPhoneInfo{
		Name:  "cjs",
		Id:    1,
		Email: "cjs_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371662",
			Type:   1,
		},
	}
	AddressBook["dh"] = &protos.IPhoneInfo{
		Name:  "dh",
		Id:    2,
		Email: "dh_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371663",
			Type:   2,
		},
	}
	AddressBook["jay"] = &protos.IPhoneInfo{
		Name:  "jay",
		Id:    3,
		Email: "jay_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371664",
			Type:   protos.IPhoneInfo_MOBILE, //eunm的坑,注意这里无论是写0还是写这个,都解析不出来
		},
	}
	AddressBook["tom"] = &protos.IPhoneInfo{
		Name:  "tom",
		Id:    4,
		Email: "tom_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371665",
			Type:   1,
		},
	}
}

2.客户端流RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

message AddressBook{
  repeated IPhoneInfo people = 1;
}

service ProdService{
  rpc GetProdStock(Person) returns (IPhoneInfo);  //上一步中的,留着也没问题
  rpc GetCStreamStock(stream Person) returns (AddressBook);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"log"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	//1.依托链接,创建rpc客户端
	c := protos.NewProdServiceClient(conn)
	//2.依托链接,获取客户端流传输器
	stream, err := c.GetCStreamStock(context.Background())
	if err != nil {
		panic(err)
	}

	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,
		}
		//3.利用stream的send实现流传输
		err := stream.Send(p)
		if err != nil {
			panic(err)
		}
	}

	recv, err := stream.CloseAndRecv() //4.结束客户端流,接收数据
	if err != nil {
		panic(err)
	}
	fmt.Println(recv)

}

服务端(把这个函数添加到上一步骤的服务端文件中即可)

func (s *server) GetCStreamStock(stream protos.ProdService_GetCStreamStockServer) error {
	book := protos.AddressBook{People: make([]*protos.IPhoneInfo, 0)}
	for {
		recv, err := stream.Recv()
		if err == io.EOF {
			return stream.SendAndClose(&book)
		}
		name := recv.GetName()
		fmt.Println(name)
		if info, ok := AddressBook[name]; ok {
			book.People = append(book.People, info)
		}
	}
}

3.服务器端流RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

message SearchPerson{
  repeated Person per = 1;
}
service ProdService{
  rpc GetProdStock(Person) returns (IPhoneInfo);  //上一步中的,留着也没问题
  rpc GetCStreamStock(stream Person) returns (AddressBook);  //上一步中的,留着也没问题
  rpc GetSStreamStock(SearchPerson) returns (stream IPhoneInfo);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"io"
	"log"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	c := protos.NewProdServiceClient(conn)
	//1.因为是服务端流模式,客户端可以把数据一次性发送过去
	lists := make([]*protos.Person, 0)
	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,
		}
		lists = append(lists, p)
	}
	//2.以服务端流接收方式,发送数据
	ackStream, err := c.GetSStreamStock(context.Background(), &protos.SearchPerson{Per: lists})
	if err != nil {
		panic(err)
	}
	//3.循环接收服务端的流数据
	for {
		recv, err := ackStream.Recv()
		if err != nil && err != io.EOF {
			panic(err)
		} else if err == io.EOF { //4.当EOF的时候代表没数据了
			break
		}

		fmt.Println(recv)
	}

}

服务端(把这个函数添加到上一步骤的服务端文件中即可)

func (s *server) GetSStreamStock(sp *protos.SearchPerson, stream protos.ProdService_GetSStreamStockServer) error {
	for _, person := range sp.Per {
		if info, ok := AddressBook[person.Name]; ok {
			err := stream.Send(info) //每次发送一部分数据
			if err != nil {
				return fmt.Errorf("error sending message to stream:%v", err)
			}
		}
	}
	return nil
}

4.双向流RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

service ProdService{ 
  rpc GetProdStock(Person) returns (IPhoneInfo);//上一步中的,留着也没问题
  rpc GetCStreamStock(stream Person) returns (AddressBook);//上一步中的,留着也没问题
  rpc GetSStreamStock(SearchPerson) returns (stream IPhoneInfo);//上一步中的,留着也没问题
  rpc GetCSStreamStock(stream Person) returns (stream IPhoneInfo);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"io"
	"log"
	"sync"
	"time"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	c := protos.NewProdServiceClient(conn)
	stream, err := c.GetCSStreamStock(context.Background())
	if err != nil {
		panic(err)
	}

	var wg sync.WaitGroup
	wg.Add(1)
	go func() { //启动流接收协程
		for {
			recv, err := stream.Recv()
			if err != nil && err != io.EOF {
				panic(err)
			} else if err == io.EOF {
				wg.Done()
				return
			}
			fmt.Println(recv)
		}
	}()

	go func() { //启动流发送协程
		for _, name := range person {
			p := &protos.Person{
				Name: name,
				Id:   1,
			}

			err := stream.Send(p)
			if err != nil {
				panic(err)
			}

			time.Sleep(time.Second)
		}
		err := stream.CloseSend()
		if err != nil {
			panic(err)
		}
	}()

	wg.Wait()
}

服务端(把这个函数添加到上一步骤的服务端文件中即可)

func (s *server) GetCSStreamStock(stream protos.ProdService_GetCSStreamStockServer) error {
	for {
		recv, err := stream.Recv()
		if err != nil && err != io.EOF {
			panic(err)
		} else if err == io.EOF {
			return nil
		}
		if info, ok := AddressBook[recv.Name]; ok {
			fmt.Println(recv.Name)
			err := stream.Send(info)
			if err != nil {
				panic(err)
			}
		}
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go语言操作grpc详细使用 的相关文章

随机推荐

  • keil中怎么添加自己的头文件,加入工程,保存路径。#include还用吗

    keil中怎么添加自己的头文件 xff0c 例如 xff1a 添加 include lt led h gt 要把它写在哪里 xff0c 保存在哪里 xff0c 才能编译后 xff0c 显示 include lt reg51 h gt inc
  • 面试题整理简历中深度学习机器学习相关的知识及linux操作系统命令

    深度学习与机器学习 都在整理关于后台的 xff0c 被问到后忘了 xff0c 尴尬 的确是我的问题 xff0c 基本的机器学习知识还是要整理一波 o inception 网络 xff1a 主要应用了深度可分离卷积 xff1a 主要用了大尺度
  • 面试可能遇到的问题野指针等解决方法

    空指针 xff1a 一般声明一个指针变量赋值为NULL xff0c 这就是空指针 xff0c 各个类型的空指针都存在确确实实的内存地址 xff0c 但是不会指向任何有效的值的内存地址 xff0c 对空指针操作 xff0c 例如访问属性和方法
  • 大规模分布式储存系统笔记(一)

    分布式储存系统的特性 xff1a 1 可扩展性 可按集群规模增长 xff0c 系统性能线性增长 xff1b 2 低成本 系统自动容错 xff0c 自动负载均衡 xff0c 运维方便 3 高性能 4 易用性 对外提供接口 数据类型 xff1a
  • 用MATLAB实现对运动物体识别与跟踪

    不得不说MATLAB的图像处理函数有点多 xff0c 但速度有时也是出奇的慢 还是想c的指针 xff0c 虽然有点危险 xff0c 但速度那是杠杠的 第二个MATLAB程序 xff0c 对运动物体的识别与追踪 这里我们主要运用帧差法实现运动
  • PS 开启GPU加速图片处理

    还认为你的电脑的速度效果比不上苹果吗 xff1f 还在嫌电脑渲染速度慢吗 xff1f 试一下 xff0c 电脑开启GPU硬件加速吧 xff01 只要有独显轻松加速 xff08 毕竟苹果笔记本要配独显电脑的价格基本上在15000以上 xff0
  • 管道鸟cortex-M4(TM4C1294)

    看到满屏的贪吃蛇 xff0c 我也来开源一个Ti开发板 xff08 TM4C1294 xff09 的游戏 将简化版的管道鸟 xff0c 根据自己玩的经历 xff0c 在cortexm4开发板上重新撸了一边 xff0c 设计思路 xff1a
  • C#连接MYSQL数据库并进行查询

    之前用MFC开发结果界面太难看被pass了 要求用C 重新来开发 gt lt 不过终于摆脱VC6 0的蛋疼操作了Y 先来连接数据库 xff08 1 xff09 用c 连接MYSQL数据库需要用到mysql connector net xff
  • binascii.Error: Incorrect padding 报错解决

    输入的base64编码字符串必须符合base64的padding规则 当原数据长度不是3的整数倍时 如果最后剩下两个输入数据 xff0c 在编码结果后加1个 61 xff1b 如果最后剩下一个输入数据 xff0c 编码结果后加2个 61 x
  • 通过过滤器链了解spring security + oauth2实现单点登录的过程

    一 系统 注意部署在同一机器 xff08 localhost xff09 上的三个应用 xff0c 为了防止存放在cookie中的JSESSIONID不被覆盖 xff0c 需要设置不同的path xff0c 可以在配置文件中指定不同的上下文
  • jetson tx2开箱上电

    期待已久的jetson tx2终于到了 xff0c 来做一个开箱 jetson tx2是英伟达的第三代GPU嵌入式开发板 前两代分别是jetson tk1和jetson tx1 jetson tk1 xff1a 绿色的版板子接口丰富 jet
  • Jetson tx2刷机过程中的坑

    暑假各种事忙得差不多后 xff0c 终于有时间拿出早就申请到的tx2 xff0c 开始刷机教程 xff0c 这两天几乎踩边了所有的坑 第一个坑 xff0c 虚拟机 一般在安装VMware虚拟机时 xff0c 建议的安装空间20GB xff0
  • python词云实现

    python的一个蛮酷炫的功能是可以轻松地实现词云 github上有关于这个项目的开源代码 xff1a https github com amueller word cloud 注意跑例程时要删除里面的wordcloud文件夹 词云的功能有
  • docker中accessTokens拉取私有git仓库

    背景 当需要git clone拉取私有库时 xff0c 传统的做法为将本机的ssh配置到gitlab中 但在docker中执行程序时需要拉取私有库 xff0c 此时无法为每个docker容器配置ssh 网上的一种方案为 xff0c 将配置好
  • Docker世界 -- 进阶篇(入门)

    一 Docker Compose 1 1 Docker Compose 介绍 1 1 1 简介 xff1a 传统的 docker 服务 xff0c 我们一般通过编写 Dockerfile 文件 xff0c 通过 build 命令创建一个镜像
  • 树莓派pico CMake工程 直接添加 .c .h文件

    假设工程名test1 xff0c 带main 的源代码文件 main c xff0c 要往工程里添加oled c oled h之类的源代码 直接添加为可执行文件 xff1a 编辑工程根目录的 CmakeLists txt add execu
  • 张量的通俗理解

    1 关于张量的四种定义 张量 在不同的运用场景下有不同的定义 xff08 1 xff09 张量是多维数组 xff0c 这个定义常见于各种人工智能软件 听起来还好理解 xff08 2 xff09 张量是某种几何对象 xff0c 不会随着坐标系
  • 如何搭建node_exporter

    如何搭建node exporter 1 观看条件 1 假设你已经看过上一篇文章 如何搭建普罗米修斯 Prometheus 2 假设你已经会搭建普罗米修斯 xff08 promethus xff09 3 上面两个假设 xff0c 只要满足一个
  • python类中初始化形式:def __init__(self)和def __init__(self, 参数1,参数2,···,参数n)区别

    前言 这两种初始化形式 xff0c 就类似于C 43 43 类中的构造函数 形式1 def init self span class token keyword class span span class token class name
  • Go语言操作grpc详细使用

    Go语言操作grpc详细使用 零 参考链接一 protobuf的详细使用二 grpc与protobuf的go文件的生成1 安装两个插件2 写proto文件3 编译proto文件 xff0c 生成go文件 三 grpc的详细使用1 一元RPC