gRPC框架

news2024/9/20 7:48:36

1、gRPC 与 Protobuf 介绍

  • 微服务架构中,由于每个服务对应的代码库是独立运行的,无法直接调用,彼此间
    的通信就是个大问题
  • gRPC 可以实现微服务, 将大的项目拆分为多个小且独立的业务模块, 也就是服务,
    各服务间使用高效的protobuf 协议进行RPC 调用, gRPC 默认使用protocol buffers,
    这是 google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格
    式如JSON)
  • 可以用 proto files 创建 gRPC 服务,用 message 类型来定义方法参数和返回类型

参考文章:gRPC教程

2、Mac下安装Protobuf和gRPC

参考文章:https://cloud.tencent.com/developer/article/2163004

brew命令安装

1. 安装的是 gRPC 的核心库
brew install grpc

2. 安装的是protocol编译器
brew install protobuf

3. 各个语言的代码生成工具,对于 Golang 来说,称为 protoc-gen-go
brew install protoc-gen-go
brew install protoc-gen-go-grpc

查看安装是否成功

apple@appledeMacBook-Pro ~ % protoc --version
libprotoc 25.1
apple@appledeMacBook-Pro ~ % protoc-gen-go --version
protoc-gen-go v1.31.0
apple@appledeMacBook-Pro ~ % protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.3.0

如果查不到指令,检查一下环境变量

export GOPATH="/Users/apple/go"
export PATH=$PATH:$GOPATH/bin

3、Demo1

3.1 目录结构

实现服务端和客户端的数据传输

├── client
│   └── client.go
├── go.mod
├── go.sum
├── proto
│   └──  user.proto
└── server
    └── server.go

3.2 user.proto编写

// 编译指令:protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/user.proto

// 版本号
syntax = "proto3";

// 生成文件所在的目录
option go_package="/proto";

// 制定生成 user.pb.go 的包名
package proto;

// 定义message服务端响应的数据格式,相当于结构体,
message UserInfoResponse {
    // 定义字段,相当于结构体的属性
    int32 id = 1;
    string name = 2;
    int32 age = 3;
    // 字段修饰符,repeated表示可以重复出现,就是可变数组,类似于切片类型
    repeated string hobbies = 4;
}

// 定义message客户端请求的数据格式,相当于结构体,
message UserInfoRequest {
    // 定义字段,相当于结构体的属性
    string name = 1;
}

// 定义一个service服务,相当于接口
service UserInfoService {
    // 定义一个rpc方法,相当于接口方法
    // 定义请求参数为UserInfoRequest,返回值为UserInfoResponse
    rpc GetUserInfo(UserInfoRequest) returns (UserInfoResponse);
}

执行编译指令

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

这是一个使用 Protocol Buffers(protobuf)和 Go gRPC 插件生成代码的示例命令。该命令根据 proto/user.proto 文件生成对应的 Go 代码。

这个命令的参数含义如下:

--go_out=.:指定生成的 Go 代码输出目录为当前目录。
--go_opt=paths=source_relative:设置生成的 Go 代码中的导入路径为相对于源文件的相对路径。
--go-grpc_out=.:指定生成的 Go gRPC 代码输出目录为当前目录。
--go-grpc_opt=paths=source_relative:设置生成的 Go gRPC 代码中的导入路径为相对于源文件的相对路径。
proto/user.proto:指定要生成代码的 protobuf 文件路径。

最后会在proto目录下生成user.pb.go和user_grpc.pb.go

  • user.pb.go:这个文件包含了用户自定义的消息类型的定义,它描述了在通信过程中需要传输的数据结构,比如用户信息、请求参数等。
  • user_grpc.pb.go:这个文件包含了用户自定义的服务接口的定义,它描述了可以远程调用的方法和参数,以及返回值等。

3.3 server服务端

package main

import (
	"context"
	"fmt"
	pb "main/proto"
	"net"

	"google.golang.org/grpc"
)

// 定义服务端实现约定的接口
type UserInfoService struct {
	pb.UnimplementedUserInfoServiceServer
}

// 实现服务端需要实现的接口
func (s *UserInfoService) GetUserInfo(ctx context.Context, req *pb.UserInfoRequest) (resp *pb.UserInfoResponse, err error) {

	// 服务端接收参数name,再进行业务操作
	name := req.Name

	if name == "zs" {
		resp = &pb.UserInfoResponse{
			Id:      1,
			Name:    name,
			Age:     18,
			Hobbies: []string{"swimming", "running"},
		}
	}

	err = nil
	return
}

func main() {
	// 1. 监听
	addr := "127.0.0.1:8080"
	lis, err := net.Listen("tcp", addr)
	if err != nil {
		fmt.Println("监听异常, err = ", err)
		return
	}

	fmt.Println("开始监听:", addr)

	// 2. 实例化gRPC
	s := grpc.NewServer()

	// 3. 在gRPC上注册微服务,第二个参数要接口类型的变量
	pb.RegisterUserInfoServiceServer(s, &UserInfoService{})

	// 4. 启动gRPC服务端
	s.Serve(lis)
}

3.4 client客户端

package main

import (
	"context"
	"fmt"
	pb "main/proto"

	"google.golang.org/grpc"
	//"google.golang.org/grpc/credentials/insecure"
)

func main() {
	// 1. 创建与gRPC服务器的连接
	addr := "127.0.0.1:8080"
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		fmt.Println("连接异常, err = ", err)
		return
	}
	defer conn.Close()

	// 2. 实例化gRPC客户端
	client := pb.NewUserInfoServiceClient(conn)

	// 3. 组装参数
	req := new(pb.UserInfoRequest)
	req.Name = "zs"

	// 4. 调用接口
	resp, err := client.GetUserInfo(context.Background(), req)
	if err != nil {
		fmt.Println("响应异常, err = ", err)
		return
	}
	fmt.Println("响应结果, resp = ", resp)
}

3.5 编译

先执行服务端,再执行客户端
在这里插入图片描述

4、Demo2

4.1 目录结构

├── client
│   └── client.go
├── go.mod
├── go.sum
├── proto
│   └── hello.proto
└── server
    └── server.go

4.2 hello.proto

// 编译指令:protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/hello.proto

syntax = "proto3";

option go_package="/proto";

package Business;

service Hello {
  rpc Say (SayRequest) returns (SayResponse);
}

message SayResponse {
  string Message = 1;
}

message SayRequest {
  string Name = 1;
}

4.3 server服务端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"main/proto"
	"net"
)

type server struct {
	proto.UnimplementedHelloServer
}

func (s *server) Say(ctx context.Context, req *proto.SayRequest) (*proto.SayResponse, error) {
	fmt.Println("request:", req.Name)
	return &proto.SayResponse{Message: "Hello " + req.Name}, nil
}

func main() {
	listen, err := net.Listen("tcp", ":8001")
	if err != nil {
		fmt.Printf("failed to listen: %v", err)
		return
	}
	s := grpc.NewServer()
	proto.RegisterHelloServer(s, &server{})
	//reflection.Register(s)

	defer func() {
		s.Stop()
		listen.Close()
	}()

	fmt.Println("Serving 8001...")
	err = s.Serve(listen)
	if err != nil {
		fmt.Printf("failed to serve: %v", err)
		return
	}
}

4.4 client客户端

package main

import (
	"bufio"
	"context"
	"fmt"
	"main/proto"
	"os"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {

	var serviceHost = "127.0.0.1:8001"

	conn, err := grpc.Dial(serviceHost, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		fmt.Println(err)
	}
	defer conn.Close()

	client := proto.NewHelloClient(conn)
	rsp, err := client.Say(context.TODO(), &proto.SayRequest{
		Name: "BOSIMA",
	})

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(rsp)

	fmt.Println("按回车键退出程序...")
	in := bufio.NewReader(os.Stdin)
	_, _, _ = in.ReadLine()
}

4.5 编译

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1312424.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DSP280049C初学(4)-FLASH烧录以及部分程序转移至RAM运行

DSP280049C初学(4)-FLASH烧录以及部分程序转移至RAM运行 实现目的:代码在RAM中调试完成后,就需要将其固化下载到FLASH中,但是FLASH中运行所有程序的话会存在计算或程序运行时间过长的问题,故还需要将部分代…

【C语言初阶】什么操作符你还没搞懂?试试这篇文章让你彻底理解各种操作符!

🎬 鸽芷咕:个人主页 🔥 个人专栏:《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想,就是为了理想的生活! 文章目录 一、 算术操作符:1.1 加减乘除 二、 移位操作符:2.1 计算机中整数的存储2.2 >> 右…

arp欺骗原理以及实现方式

我们知道了arp的作用,那么此时我们怎么可以用他来进行攻击呢?在一个局域网中,我们怎么实现呢? 原理: 这样B就可以做到中间人了,可以接受到两个主机的数据了。换句话来说,在同一个局域网内&…

JVM 详解(JVM组成部分、双亲委派机制、垃圾回收算法、回收器、回收类型、了解调优思路)

目录 JVM 详解(JVM组成部分、双亲委派机制、垃圾回收算法、回收器、回收类型、了解调优思路)1、概念:什么是 JVM ?JVM 的作用? 2、JVM 的主要组成部分?类加载器(Class Loader):简单…

坚鹏:美国智库认为中国在70%战略产业里领先,美国正迅速衰落

【重榜】2023年12月13日,美国智库信息技术与创新基金会(ITIF)发布重榜报告,认为中国在70%战略产业里领先,美国正迅速衰落。美国智库ITIF认为在计算机和电子产品、化工品、机器设备、机动车、基本金属、金属制品、电气设…

linux 网络子系统 摘要

当你输入一个网址并按下回车键的时候,首先,应用层协议对该请求包做了格式定义;紧接着传输层协议加上了双方的端口号,确认了双方通信的应用程序;然后网络协议加上了双方的IP地址,确认了双方的网络位置;最后链路层协议加上了双方的M…

精细化工ERP系统是什么?精细化工ERP软件包含哪些模块

化工是比较特殊的行业,日常的生产经营活动比较繁杂,传统的手工管理模式逐渐不能满足现代化工管理需求。进入信息化时代,如何顺应现代化工市场发展,是摆在很多化工企业面前的难题。 随着行业竞争愈加激烈,各种成本的上…

Word写大论文常见问题(持续更新)

脚注横线未定格 解决方案:“视图”-“草图”,“引用”-“显示备注”-选择“脚注分隔符”,把横线前的空格删掉。

基于Java SSM框架实现抗疫医疗用品销售系统项目【项目源码+论文说明】

基于java的SSM框架实现抗疫医疗用品销售系统演示 摘要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,抗疫医疗用品销售平台当然也不能排除在外。抗疫医疗用品销售平台是以实…

亿欧网首届“元创·灵镜”科技艺术节精彩纷呈,实在智能AI Agent智能体展现硬核科技图景

12月4日-10日,持续一周的首届“元创灵镜”科技艺术节在海南陵水香水湾拉开帷幕,虚实交互创造出的“海岛之镜”开幕式呈现出既真实又虚幻的未来感,融入前沿科技元素的艺术装置作品在“虚实之镜&自然生长”科技艺术展诠释着浪漫想象&#x…

爬虫chrome浏览器抓包说明

chrome浏览器抓包说明 目标:掌握chrome在爬虫中的使用 1. 新建隐身窗口(无痕窗口) 作用:在打开无痕窗口的时候,第一次请求某个网站是没有携带cookie的,和代码请求一个网站一样,这样就能够尽可…

jpa 修改信息拦截

实现目标springbootJPA 哪个人,修改了哪个表的哪个字段,从什么值修改成什么值 Component // 必须加 Slf4j Configurable(autowire Autowire.BY_TYPE) public class AuditingEntityListener {// 线程变量,保存修改前的 objectprivate Thre…

PyVMomi 克隆虚拟机时将磁盘改为Thin模式

需求介绍: 之前已经使用pyvmomi库实现了虚拟机的自动备份,不过由于备份的虚拟机都是较为重要的系统,磁盘都是厚置备模式,终于有一天,备份目标的空间不够了,导致几个虚拟机无法备份。在不想增加磁盘的情况下…

Linux16 ftp文件服务区、vsftpd文件系统服务安装、lftp客户端安装、NFS远程共享存储

目录 一、FTP基础ftp主动模式ftp被动模式 二、vsftpd配置共享目录编辑配置文件使用windows 访问 三、客户端安装 (lftp)匿名用户的一些操作(lftp {ip})ftp配置本地用户登录配置本地用户ftp配置文件 lftp操作 NFS远程共享存储安装n…

Leetcode—380.O(1) 时间插入、删除和获取随机元素【中等】

2023每日刷题&#xff08;五十七&#xff09; Leetcode—380.O(1) 时间插入、删除和获取随机元素 算法思想 实现代码 class RandomizedSet { public:vector<int> nums;unordered_map<int, int> dict;RandomizedSet() {srand((unsigned)time(NULL));}bool insert(…

如何为您的项目选择最优化的 RTLS系统方案

到 2030 年&#xff0c;实时定位市场预计将是当今市场规模的 10 倍&#xff1b;各种全球宏观经济趋势加剧了 RTLS 的指数增长&#xff0c;其中包括&#xff1a; 企业投资回报率的压力增加&#xff0c;从而扩大了对数字化、简化数据和分析的需求&#xff0c;尤其是在 COVID-19 之…

PS扣印章

1 印章区域图片 2 3 吸取印章上的颜色&#xff0c;调节容差&#xff0c;尽量小一点&#xff0c;过大会将背景也进来 4 CtrlJ 把选区复制出来&#xff0c;这个印章图层比较淡&#xff0c;可以通过多复制几个叠加或通过叠加模式来调节。 5 对几个图层选中后CtrlE合并图层 6 选…

Linux查询指定时间点段日志Linux查询指定文件

Linux服务器高效查询日志查询文件 Ⅰ、常用几种日志查询语法Ⅱ、常用几种查询语法 Ⅰ、常用几种日志查询语法 #查询某日志前xx行日志 head -n 行数 日志文件名 #查询某日志后xx行日志 tail -n 行数 日志文件名 #查询固定时间点日志&#xff08;前提是这个时间点确实有日志输出…

观测云产品更新 | 智能监控、数据访问、指标分析等优化

观测云更新 监控 > 智能监控 1、新增「智能监控」&#xff0c;您只需要在检测规则中设置好检测范围和通知对象即可快速开启监控。支持「主机监控」、「日志监控」、「应用监控」&#xff0c;每个监控包含的检测项如下&#xff1a; 智能监控器检测项主机监控CPU的突增/突降…