当前位置: 首页 > article >正文

gRPC 的四种通信模式完整示例

gRPC 的四种基本通信模式,包括完整的 .proto 文件定义和 Go 语言实现代码:

1. 简单 RPC (Unary RPC) - 请求/响应模式

客户端发送单个请求,服务端返回单个响应

calculator.proto

protobuf

syntax = "proto3";package calculator;service Calculator {// Unary RPCrpc Add (AddRequest) returns (AddResponse) {}
}message AddRequest {int32 a = 1;int32 b = 2;
}message AddResponse {int32 result = 1;
}

服务端实现 (Go)

package mainimport ("context""log""net""google.golang.org/grpc"pb "path/to/calculator"
)type server struct {pb.UnimplementedCalculatorServer
}func (s *server) Add(ctx context.Context, req *pb.AddRequest) (*pb.AddResponse, error) {result := req.A + req.Breturn &pb.AddResponse{Result: result}, nil
}func main() {lis, err := net.Listen("tcp", ":50051")if err != nil {log.Fatalf("failed to listen: %v", err)}s := grpc.NewServer()pb.RegisterCalculatorServer(s, &server{})log.Printf("server listening at %v", lis.Addr())if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
}

客户端实现 (Go)

package main
import ("context""log""os""time""google.golang.org/grpc"pb "path/to/calculator"
)func main() {conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()c := pb.NewCalculatorClient(conn)ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()// Unary RPC 调用r, err := c.Add(ctx, &pb.AddRequest{A: 5, B: 3})if err != nil {log.Fatalf("could not add: %v", err)}log.Printf("Result: %d", r.GetResult())
}

2. 服务端流式 RPC (Server Streaming RPC)

客户端发送单个请求,服务端返回流式响应

calculator.proto

// Server Streaming RPC
rpc PrimeFactors (PrimeRequest) returns (stream PrimeResponse) {
message PrimeRequest {int32 number = 1;
}message PrimeResponse {int32 factor = 1;
}

服务端实现

func (s *server) PrimeFactors(req *pb.PrimeRequest, stream pb.Calculator_PrimeFactorsServer) error {n := req.GetNumber()factor := 2for n > 1 {if n%int32(factor) == 0 {// 发送因数stream.Send(&pb.PrimeResponse{Factor: int32(factor)})n /= int32(factor)} else {factor++}}return nil
}

客户端实现

// 服务端流式调用
stream, err := c.PrimeFactors(ctx, &pb.PrimeRequest{Number: 120})
if err != nil {log.Fatalf("could not get prime factors: %v", err)
}log.Print("Prime factors of 120:")
for {res, err := stream.Recv()if err == io.EOF {break}if err != nil {log.Fatalf("error receiving factor: %v", err)}log.Printf("- %d", res.GetFactor())
}

3. 客户端流式 RPC (Client Streaming RPC)

客户端发送流式请求,服务端返回单个响应

calculator.proto 

// Client Streaming RPC
rpc Average (stream AverageRequest) returns (AverageResponse) {}
​​​​​​​message AverageRequest {double number = 1;
}message AverageResponse {double average = 1;
}

服务端实现

func (s *server) Average(stream pb.Calculator_AverageServer) error {sum := 0.0count := 0for {req, err := stream.Recv()if err == io.EOF {// 计算平均值并返回响应average := sum / float64(count)return stream.SendAndClose(&pb.AverageResponse{Average: average})}if err != nil {return err}sum += req.GetNumber()count++}
}

客户端实现

// 客户端流式调用
avgStream, err := c.Average(ctx)
if err != nil {log.Fatalf("could not calculate average: %v", err)
}numbers := []float64{1.5, 2.5, 3.5, 4.5, 5.5}
for _, num := range numbers {if err := avgStream.Send(&pb.AverageRequest{Number: num}); err != nil {log.Fatalf("error sending number: %v", err)}
}avgRes, err := avgStream.CloseAndRecv()
if err != nil {log.Fatalf("error receiving average: %v", err)
}
log.Printf("Average: %.2f", avgRes.GetAverage())

4. 双向流式 RPC (Bidirectional Streaming RPC)

客户端和服务端同时发送流式消息

calculator.proto 

// Bidirectional Streaming RPC
rpc Chat (stream ChatMessage) returns (stream ChatMessage) {}
message ChatMessage {string text = 1;int64 timestamp = 2;
}

服务端实现

func (s *server) Chat(stream pb.Calculator_ChatServer) error {for {in, err := stream.Recv()if err == io.EOF {return nil}if err != nil {return err}// 模拟处理消息log.Printf("Received: %s", in.GetText())response := &pb.ChatMessage{Text: "Echo: " + in.GetText(),Timestamp: time.Now().UnixNano(),}// 发送响应if err := stream.Send(response); err != nil {return err}}
}

客户端实现

// 双向流式调用
chatStream, err := c.Chat(ctx)
if err != nil {log.Fatalf("could not start chat: %v", err)
}// 接收消息的goroutine
go func() {for {res, err := chatStream.Recv()if err == io.EOF {return}if err != nil {log.Fatalf("error receiving message: %v", err)}log.Printf("Server: %s (time: %d)", res.GetText(), res.GetTimestamp())}
}()// 发送消息
messages := []string{"Hello", "How are you?", "Goodbye"}
for _, msg := range messages {if err := chatStream.Send(&pb.ChatMessage{Text: msg,Timestamp: time.Now().UnixNano(),}); err != nil {log.Fatalf("error sending message: %v", err)}time.Sleep(1 * time.Second)
}chatStream.CloseSend()

项目结构建议

grpc-demo/
├── proto/
│   └── calculator.proto
├── server/
│   └── main.go
├── client/
│   └── main.go
└── gen/└── calculator.pb.go  # 自动生成的代码

编译和运行步骤

  1. 安装依赖:

    go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
  2. 生成 gRPC 代码:

protoc --go_out=./gen --go_opt=paths=source_relative \--go-grpc_out=./gen --go-grpc_opt=paths=source_relative \proto/calculator.proto
  1. 启动服务端:

    cd server
    go run main.go
  2. 启动客户端:

    cd client
    go run main.go

各模式适用场景总结

模式特点适用场景
简单RPC1请求 → 1响应常规API调用,如用户验证、数据查询
服务端流式1请求 → N响应实时数据推送、大文件下载、实时监控
客户端流式N请求 → 1响应批量上传、日志收集、传感器数据汇总
双向流式N请求 ↔ N响应实时聊天、游戏状态同步、双向数据流处理

这些示例展示了 gRPC 的核心通信模式,您可以根据实际需求组合使用这些模式构建复杂的分布式系统。

相关文章:

gRPC 的四种通信模式完整示例

gRPC 的四种基本通信模式,包括完整的 .proto 文件定义和 Go 语言实现代码: 1. 简单 RPC (Unary RPC) - 请求/响应模式 客户端发送单个请求,服务端返回单个响应 calculator.proto protobuf syntax "proto3";package calculato…...

C#中Struct与IntPtr转换:实用扩展方法

C#中Struct与IntPtr转换:实用扩展方法 在 C# 编程的世界里,我们常常会遇到需要与非托管代码交互,或者进行一些底层内存操作的场景。这时,IntPtr类型就显得尤为重要,它可以表示一个指针或句柄,用来指向非托…...

Web安全:XSS、CSRF等常见漏洞及防御措施

Web安全:XSS、CSRF等常见漏洞及防御措施 一、XSS(跨站脚本攻击) 定义与原理 XSS攻击指攻击者将恶意脚本(如JavaScript、HTML标签)注入到Web页面中,当用户访问该页面时,脚本在浏览器端执行&…...

Java基础之数组(附带Comparator)

文章目录 基础概念可变参数组数组与ListComparator类1,基本概念2,使用Comparator的静态方法(Java 8)3,常用Comparator方法4,例子 排序与查找数组复制其他 基础概念 int[] anArray new int[10];只有创建对象时才会使用new关键字,所以数组是个…...

计算机组成与体系结构:补码数制二(Complementary Number Systems)

目录 4位二进制的减法 补码系统 🧠减基补码 名字解释: 减基补码有什么用? 计算方法 ❓为什么这样就能计算减基补码 💡 原理揭示:按位减法,模拟总减法! 那对于二进制呢?&…...

C#使用MindFusion.Diagramming框架绘制流程图(2):流程图示例

上一节我们初步介绍MindFusion.Diagramming框架 C#使用MindFusion.Diagramming框架绘制流程图(1):基础类型-CSDN博客 这里演示示例程序: 新建Windows窗体应用程序FlowDiagramDemo,将默认的Form1重命名为FormFlowDiagram. 右键FlowDiagramDemo管理NuGet程序包 输入MindFusio…...

【物联网-ModBus-RTU

物联网-ModBus-RTU ■ 优秀博主链接■ ModBus-RTU介绍■(1)帧结构■(2)查询功能码 0x03■(3)修改单个寄存器功能码 0x06■(4)Modbus RTU 串口收发数据分析 ■ 优秀博主链接 Modbus …...

Java应用10(客户端与服务器通信)

Java客户端与服务器通信 Java提供了多种方式来实现客户端与服务器之间的通信,下面我将介绍几种常见的方法: 1. 基于Socket的基本通信 服务器端代码 import java.io.*; import java.net.*;public class SimpleServer {public static void main(String…...

STM32学习之I2C(理论篇)

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...

【C/C++】algorithm清单以及适用场景

文章目录 algorithm清单以及适用场景1 算法介绍1.1 分类1.2 非修改序列算法1.3 修改序列算法1.4 排序与堆算法1.5 集合操作算法&#xff08;要求有序&#xff09;1.5 查找算法1.6 二分查找算法&#xff08;有序区间&#xff09;1.7 去重与分区算法1.8 数值算法 <numeric>…...

Python_day47

作业&#xff1a;对比不同卷积层热图可视化的结果 一、不同卷积层的特征特性 卷积层类型特征类型特征抽象程度对输入的依赖程度低层卷积层&#xff08;如第 1 - 3 层&#xff09;边缘、纹理、颜色、简单形状等基础特征低高&#xff0c;直接与输入像素关联中层卷积层&#xff08…...

如何在mac上安装podman

安装 Podman 在 macOS 上 在 macOS 上安装 Podman 需要使用 Podman 的桌面客户端工具 Podman Desktop 或通过 Homebrew 安装命令行工具。 使用 Homebrew 安装 Podman&#xff1a; (base) ninjamacninjamacdeMacBook-Air shell % brew install podman > Auto-updating Hom…...

小黑一层层削苹果皮式大模型应用探索:langchain中智能体思考和执行工具的demo

引言 小黑黑通过探索langchain源码&#xff0c;设计了一个关于agent使用工具的一个简化版小demo&#xff08;代码可以跑通&#xff09;&#xff0c;主要流程&#xff1a; 1.问题输入给大模型。 2.大模型进行思考&#xff0c;输出需要执行的action和相关思考信息。 3.通过代理&…...

CppCon 2015 学习:Intro to the C++ Object Model

这段代码展示了使用 make 工具来编译 C 程序的简单过程。 代码和步骤解析&#xff1a; C 代码&#xff08;intro.cpp&#xff09;&#xff1a;#include <iostream> int main() { std::cout<<"hello world\n"; } 这是一个简单的 C 程序&#xff0c;它包…...

Go 语言中的 make 函数详解

Go 语言中的 make 函数详解 make 是 Go 语言中的一个​​内置函数​​&#xff0c;用于​​初始化切片&#xff08;slice&#xff09;、映射&#xff08;map&#xff09;和通道&#xff08;channel&#xff09;​​这些引用类型。这些类型必须在使用前通过 make 初始化&#x…...

阿里云ACP云计算备考笔记 (4)——企业应用服务

目录 第一章 企业应用概览 第二章 云解析 1、云解析基本概念 2、域名管理流程 3、云解析记录类型 4、域名管理 ① 开启注册局安全锁 ② 域名赎回 第二章 内容分发网络CDN 1、CDN概念 2、使用CDN前后对比 3、使用CDN的优势 4、阿里云CDN的优势 5、配置网页性能优化…...

用 NGINX 构建高效 SMTP 代理`ngx_mail_smtp_module`

一、模块定位与作用 协议代理 NGINX 监听指定端口&#xff08;如 25、587、465 等&#xff09;&#xff0c;接收客户端的 SMTP 会话请求。代理层在会话中透明转发客户端的 EHLO、MAIL FROM、RCPT TO、DATA 等命令到后端 MTA。 认证控制 通过 smtp_auth 指令指定允许的 SASL 认…...

【前端】常用组件的CSS

1. button的样式修改 每个环节有五个不同的状态:link,hover,active,focus和visited. Link是正常的外观,hover当你鼠标悬停时,active是单击它时的状态,focus跟随活动状态,visited是你在最近点击的链接未聚焦时结束的状态。 纯CSS 以下为例子&#xff0c;按下后从浅紫到深紫。注…...

【华为云学习与认证】以华为云物联网为基座的全栈开发(从物联网iot平台模块到应用展示、数据分析、机器学习、嵌入式开发等)的系统性学习与认证路线

总目标 学习以华为云物联网为基座的全栈开发&#xff08;从物联网iot平台模块到应用展示、数据分析、机器学习、嵌入式开发等&#xff09;的系统性学习与认证路线。计划包含阶段学习、技术文档、实操实际操作、开发路径与考证规划&#xff0c;提供职业生涯基础性规划。 注意&…...

OpenCV 键盘响应来切换图像

一、知识点 1、int waitKey(int delay 0); (1)、等待按键。 等待指定的毫秒数&#xff0c;返回按键的ASCII码。 (2)、返回值: int型&#xff0c;表示按键ASCII码。 若没有按键&#xff0c;指定时间过去&#xff0c;返回-1。 (3)、参数delay: 等待时间&#xff0c;单位毫…...

ARM SMMUv3简介(一)

1.概述 SMMU&#xff08;System Memory Management Unit&#xff0c;系统内存管理单元&#xff09;是ARM架构中用于管理设备访问系统内存的硬件模块。SMMU和MMU的功能类似&#xff0c;都是将虚拟地址转换成物理地址&#xff0c;不同的是MMU转换的虚拟地址来自CPU&#xff0c;S…...

C#提取CAN ASC文件时间戳:实现与性能优化

C#提取CAN ASC文件时间戳&#xff1a;实现与性能优化 在汽车电子和工业控制领域&#xff0c;CAN总线是最常用的通信协议之一。而ASC&#xff08;ASCII&#xff09;文件作为CAN总线数据的标准日志格式&#xff0c;广泛应用于数据记录和分析场景。本文将深入探讨如何高效地从CAN…...

hadoop集群datanode启动显示init failed,不能解析hostname

三个datanode集群&#xff0c;有一个总是起不起来。去查看log显示 Initialization failed for Block pool BP-1920852191-192.168.115.154-1749093939738 (Datanode Uuid 89d9df36-1c01-4f22-9905-517fee205a8e) service to node154/192.168.115.154:8020 Datanode denied com…...

Android 视图系统入门指南

1. View&#xff1a;界面的最小单位 本质&#xff1a;屏幕上的一个矩形区域&#xff0c;能显示内容或接收触摸。比喻&#xff1a;就像乐高积木&#xff0c;是组成界面的最小单位。常见子类&#xff1a; TextView&#xff08;文字积木&#xff09;、Button&#xff08;按钮积木…...

浏览器工作原理05 [#] 渲染流程(上):HTML、CSS和JavaScript是如何变成页面的

引用 浏览器工作原理与实践 一、提出问题 在上一篇文章中我们介绍了导航相关的流程&#xff0c;那导航被提交后又会怎么样呢&#xff1f;就进入了渲染阶段。这个阶段很重要&#xff0c;了解其相关流程能让你“看透”页面是如何工作的&#xff0c;有了这些知识&#xff0c;你可…...

青少年编程与数学 01-011 系统软件简介 03 NetWare操作系统

青少年编程与数学 01-011 系统软件简介 03 NetWare操作系统 一、历史背景二、核心架构三、关键功能四、管理工具五、客户端支持六、版本演变七、衰落原因八、遗产与影响总结 摘要&#xff1a;NetWare 是早期网络操作系统的巅峰之作&#xff0c;其高性能文件服务、目录管理和容错…...

AI编程提示词

你是 IDE 的 AI 编程助手&#xff0c;遵循核心工作流&#xff08;研究 -> 构思 -> 计划 -> 执行 -> 评审&#xff09;用中文协助用户&#xff0c;面向专业程序员&#xff0c;交互应简洁专业&#xff0c;避免不必要解释。[沟通守则] 1. 响应以模式标签 [模式&#…...

Android学习总结-GetX库常见问题和解决方案

GetX库的常见问题 ​路由管理&#xff1a;Get.to() 后页面不跳转或卡顿&#xff1f;​​ ​问题&#xff1a;​​ 明明调用了 Get.to(NextPage())&#xff0c;但页面没反应&#xff0c;或者感觉有延迟卡顿。这可能发生在较复杂的页面树或低端设备上。​原因&#xff1a;​​ ​…...

|从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面

&#x1f411; |从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面 &#x1f411; 文章目录 &#x1f411; |从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面 &#x1f411;♈前言♈♈调取Deepseek大模型♈♒准备工作♒♒调用API♒ ♈将模型嵌入到ui界面中♈♈…...

React 中 HTML 插入的全场景实践与安全指南

在 React 开发过程中&#xff0c;我们常常会遇到需要插入 HTML 内容的场景。比如将服务端返回的富文本渲染到页面&#xff0c;还有处理复杂的 UI 结构&#xff0c;正确的 HTML 插入方式不仅影响页面展示效果&#xff0c;更关乎应用的安全性。 本文将详细探讨 React 中插入 HTM…...