[gRPC实现go调用go]

news2024/10/7 8:32:08

1什么是RPC

RPC:Remote Procedure Call,远程过程调用。简单来说就是两个进程之间的数据交互。正常服务端的接口服务是提供给用户端(在Web开发中就是浏览器)或者自身调用的,也就是本地过程调用。和本地过程调用相对的就是:假如两个服务端不在一个进程内怎么进行数据交互?使用RPC。尤其是现在微服务的大量实践,服务与服务之间的调用不可避免,RPC更显得尤为重要

在这里插入图片描述

上图描述了一个RPC的完整调用流程:
1:client向client stub发起方法调用请求。
2:client stub接收到请求后,将方法名,请求参数等信息进行编码序列化。
3:client stub通过配置的ip和端口使用socket通过网络向远程服务器server发起请求。
4:远程服务器server接收到请求,解码反序列化请求信息。
5:server将请求信息交给server stub,server stub找到对应的本地真实方法实现。
6:本地方法处理调用请求并将返回的数据交给server stub。
7:server stub 将数据编码序列化交给操作系统内核,使用socket将数据返回。
8:client端socket接收到远程服务器的返回信息。
9:client stub将信息进行解码反序列化。
10:client收到远程服务器返回的信息。

上图中有一个stub(存根)的概念。stub负责接收本地方法调用,并将它们委托给各自的具体实现对象。server端stub又被称为skeleton(骨架)。可以理解为代理类。而实际上基于Java的RPC框架stub基本上也都是使用动态代理。我们所说的client端和server端在RPC中一般也都是相对的概念。
而所谓的RPC框架也就是封装了上述流程中2-9的过程,让开发者调用远程方法就像调用本地方法一样。

2. gRPC的原理

gRPC是Google的开源产品,是跨语言的通用型RPC框架,使用Go语言编写。 Java语言的应用同样使用了Netty做网络通信,Go采用了Goroutine做网络通信。序列化方式采用了Google自己开源的Protobuf。请求的调用和返回使用HTTP2的Stream。

一个RPC框架必须有两个基础的组成部分:数据的序列化和进程数据通信的交互方式。

对于序列化gRPC采用了自家公司开源的Protobuf。Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。似乎和我们熟悉的JSON类似,但其实着重点有些本质的区别。JSON主要是用于数据的传输,因为它轻量级,可读性好,解析简单。Protobuf主要是用于跨语言的IDL,它除了和JSON、XML一样能定义结构体之外,还可以使用自描述格式定于出接口的特性,并可以使用针对不同语言的protocol编译器产生不同语言的stub类。所以天然的适用于跨语言的RPC框架中(非常重要)

而关于进程间的通讯,无疑是Socket。Java方面gRPC同样使用了成熟的开源框架Netty。使用Netty Channel作为数据通道。传输协议使用了HTTP2。
通过以上的分析,我们可以将一个完整的gRPC流程总结为以下几步:

● 通过.proto文件定义传输的接口和消息体。
● 通过protocol编译器生成server端和client端的stub程序。
● 将请求封装成HTTP2的Stream。
● 通过Channel作为数据通信通道使用Socket进行数据传输。

3 实践开始

下面我们使用代码基于以上的步骤来实现一个简单gRPC。我们用Go实现server端,Java作为client端来实现。

3.1 安装Protocol Buffers,定义.proto文件

下载Protocol Buffers:https://github.com/protocolbuffers/protobuf/releases
检查安装

protoc --version

定义一个simple.proto,这也是后续实现gRPC的基础:

syntax = "proto3"; //定义了我们使用的Protocol Buffers版本。

option go_package = "./;simple";//***在java端请注释本行***

 //表明我们定义了一个命名为Simple的服务(接口),内部有一个远程rpc方法,名字为SayHello。
 //我们只要在server端实现这个接口,在实现类中书写我们的业务代码。在client端调用这个接口。
 service Simple{
    rpc SayHello(HelloRequest) returns (HelloReplay){}
 }

 //请求的结构体
 message HelloRequest{
     string name = 1;
 }
 //返回的结构体
 message HelloReplay{
     string message = 1;
 }

3.2 在Go端实现server

根据官方文档使用如下命令安装针对Go的gRPC:

go get -u google.golang.org/grpc

建立Go的project:go-server-grpc,然后将前面写的simple.proto放入项目proto的package中。
cd到proto目录执行如下命令:

protoc --go_out=plugins=grpc:. simple.proto

这样就将simple.proto编译成了Go语言对应的stub程序了。
在这里插入图片描述

随后我们就可以写我们server端的代码了:main.go。
以下的代码都是模板代码,main函数是socket使用Go的标准实现。作为开发者我们只关注远程服务提供的具体接口实现即可。
我们可以在生成的simple.pb.go中发现需要实现的接口:

// 客户端调用的接口
type SimpleClient interface {
	SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error)
}

type simpleClient struct {
	cc grpc.ClientConnInterface
}

func NewSimpleClient(cc grpc.ClientConnInterface) SimpleClient {
	return &simpleClient{cc}
}

func (c *simpleClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error) {
	out := new(HelloReplay)
	err := c.cc.Invoke(ctx, "/Simple/SayHello", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// 服务端需要实现的接口
type SimpleServer interface {
	SayHello(context.Context, *HelloRequest) (*HelloReplay, error)
}

之后我们在main.go中实现接口:

package main

import (
    "context"
    "grpc-server/proto"//引入对应的包
    "fmt"
    "net"
    "log"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
)
//定义接下来要开放的socket的端口
const(
    port = ":50051"
)

type server struct{}

func (s *server) SayHello(ctx context.Context,req *simple.HelloRequest) (*simple.HelloReplay, error){

    fmt.Println(req.Name)

    return &simple.HelloReplay{Message:"hello =======> " + req.Name},nil
}

之后填写main方法:

func main() {
	//创建一个socket监听
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatal("fail to listen")
	}
	//新建一个grpc服务器
	s := grpc.NewServer()
	//使用 simple.RegisterSimpleServer 函数将实现了 SimpleServer 接口的 server 对象注册到 gRPC 服务器(s)上
	simple.RegisterSimpleServer(s, &server{})
	//使用 reflection.Register 函数将 gRPC 服务器(s)注册到反射服务中。这样,可以通过 gRPC 提供的工具来动态地查看和调用服务器上的服务。
	reflection.Register(s)
	//使用 s.Serve 方法启动 gRPC 服务器(s),开始接受来自客户端的连接请求并提供服务。如果启动过程中出现错误,程序会输出一条错误信息并终止运行。
	if err := s.Serve(lis); err != nil {
		log.Fatal("fail to server")
	}
}

目前服务端已经完成了。

3.3 在Go端实现client

package main

import (
	"context"
	"fmt"
	simple "go-server-grpc/proto"
	"log"

	"google.golang.org/grpc"
)

const (
	address = "localhost:50051"
)

func main() {
	// 创建与服务器的连接
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("无法连接到服务器:%v", err)
	}
	defer conn.Close()
	// 创建一个新的 gRPC 客户端
	client := simple.NewSimpleClient(conn)
	// 构建请求
	request := &simple.HelloRequest{
		Name: "John",
	}
	// 调用 gRPC 方法
	response, err := client.SayHello(context.Background(), request)
	if err != nil {
		log.Fatalf("调用 gRPC 方法失败:%v", err)
	}
	// 打印响应
	fmt.Println(response.Message)
}

需要先启动服务端,再启动客户端就可以看到效果。
输出:hello=======>John

4.下次预告

实现Java作为客户端调用go服务端的服务

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

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

相关文章

ardupilot开发 --- git 篇

一些概念 工作区:就是你在电脑里能看到的目录;暂存区:stage区 或 index区。存放在 :工作区 / .git / index 文件中;版本库:本地仓库,存放在 :工作区 / .git 中 关于 HEAD 是所有本地…

FPGA设计时序分析概念之Timing Arc

目录 1.1 Timing Arc概念 1.2 Timing Arcs的类型 1.3 Timing Sense(时序感知) 1.4 参考资料 1.1 Timing Arc概念 在时序工具对设计进行时序分析时,经常会看到一个概念Timing Arch(时序弧)。Timing Arc是一个信号一个单元Cell的输入引脚Pin到该单元输出引脚Outpu…

Python面向对象基础

Python面向对象基础 一、概念1.1面向对象的设计思想1.2 面向过程和面向对象1.2.1 面向过程1.2.2 面向对象1.2.3 面向过程和面向对象的优缺点 二、类和对象2.1 概念2.2 类的定义2.3 对象的创建2.3.1 类中未定义构造函数2.3.2 类中定义构造函数 2.4 类的设计 三、类中的成员3.1 变…

SAP UI5 walkthrough step3 Controls

在上一步&#xff0c;我们是直接用index.html 中的body 里面的DIVision去输出 hello world&#xff0c; 在这个章节&#xff0c;我们将用SAP UI5 的标准控件 sap/m/Text 首先&#xff0c;我们去修改 webapp/index.html <!DOCTYPE html> <html> <head><…

电脑软件:TileIconifier开始菜单美化工具介绍

目录 一、 软件介绍 二、软件功能 三、使用说明 四、软件下载 一、 软件介绍 TileIconifier是一款简单易用的win10开始菜单美化软件&#xff0c;该程序具备了简单直观的操作界面&#xff0c;打开软件后&#xff0c;您可以在快捷方式列表下选择要美化的快捷方式&#xff0c;…

年底不同外贸客户催单模板分享

最近工厂又爆单了&#xff0c;有些小的订单都没时间管了。时间过得很快&#xff0c;眼看就剩一个多月就春节&#xff0c;大家可以抓住这段时间催一下还有机会成单的客户&#xff0c;好为来年做准备&#xff01; 1.老客户模板 Dear xxx, Greetings. Do you have any new inqu…

springboot 集成Dubbo2.7.8 ,连接zookeeper 提示错误 zookeeper not connected

Dubbo 连接zookeeper时&#xff0c;提示“zookeeper not connected” java.lang.IllegalStateException: zookeeper not connectedat org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:83) ~[dubbo-2.7.8.jar:2.…

YouTube网红营销:出海品牌扩大影响力的关键

随着数字媒体的兴起&#xff0c;社交媒体已成为品牌与消费者之间建立联系的重要桥梁。其中&#xff0c;YouTube作为全球最大的视频分享平台&#xff0c;不仅拥有庞大的用户群体&#xff0c;还聚集了众多有影响力的网红。这些网红在各自的领域内拥有强大的话语权和号召力&#x…

需求产生技术,什么是光电混合缆?

光电混合缆是一种集成了光纤和导电铜线的混合形式的电缆&#xff0c;可以用一根线缆同时解决数据传输和设备供电的问题。在园区网络中&#xff0c;光电混合缆主要用于完成交换机与AP或远端模块之间的连接&#xff0c;用一根线缆同时完成AP或远端模块的数据传输和PoE供电。 随着…

快解析结合智邦国际使用教程

北京智邦国际软件技术有限公司&#xff0c;是经中华人民共和国工业和信息化部以及北京经济和信息化委员会评定和审核的双软企业&#xff0c;国家重点支持的高新技术企业。 十几年来致力于企业信息化&#xff0c;主要从事ERP、CRM、项目管理、人资管理、移动应用等企业管理软件的…

游戏王的题解

目录 原题&#xff1a; 时间&#xff1a;1s 空间&#xff1a;256M 题目描述 输入格式 输出格式 样例输入 样例输出 题目大意&#xff1a; 主要思路&#xff1a; dp转移&#xff1a; dp初始化&#xff1a; 代码&#xff1a; 原题&#xff1a; 时间&#xff1a;1s …

敏捷开发迭代缺陷统计的重要性

在敏捷开发中&#xff0c;迭代缺陷统计具有重要性&#xff0c;对团队和项目具有多方面的影响&#xff1a; 早期发现和解决问题&#xff1a; 迭代缺陷统计允许团队及时识别和定位在迭代中出现的问题。这有助于早期解决问题&#xff0c;避免问题扩大化&#xff0c;并最大程度地减…

MTU与MSS

MTU&#xff1a;一个网络包的最大长度&#xff0c;以太网中一般为1500各字节。 MSS&#xff1a;除去头部之后&#xff0c;一个网络包所能容纳的TCP数据的最大长度。 应用程序调用write后&#xff0c;将要发送的数据被交给TCP/IP协议栈进行。 协议栈不关心应用的数据内容&…

给你的Python程序添点Emoji魔法:使用Emoji模块增添趣味和个性!

当你想给你的Python程序增添一些趣味和个性时&#xff0c;Emoji模块是一个很有用的工具。Emoji模块允许你在Python中使用各种表情符号&#xff0c;从笑脸到动物&#xff0c;甚至是食物和天气等。在本篇博客中&#xff0c;我们将介绍如何在Python中使用Emoji模块&#xff0c;并展…

动态规划——完全背包问题(公式推导,组合、排列)

本文章是对于完全背包 一些题型(如题目所示&#xff0c;组合、排列和最小值类型)的总结和理解&#xff0c;依次记录一下&#xff0c;方便回顾与复习。 本文章是基于个人所总结 实现的&#xff0c;但在其中遇到了一些疑惑与困难&#xff0c;所以总结一篇与完全背包相关的问题。 …

本地数据备份与FTP远程数据迁移

数据是电脑中最重要的东西。为了保证数据安全&#xff0c;我们经常会对数据进行备份。之前一直采用将重要数据拷贝至移动硬盘的方式实现备份&#xff0c;实现简单但每次都需要把所有文件拷贝一次&#xff0c;当文件很大时效率较低。 因此&#xff0c;考虑使用 FreeFileSync 软…

【Flink系列五】Checkpoint及Barrier原理

本章内容 一致性检查点从检查点恢复状态检查点实现算法-barrier保存点Savepoint状态后端&#xff08;state backend&#xff09; 本文先设置一个前提&#xff0c;流处理的数据都是可回放的&#xff08;可以理解成消费的kafka的数据&#xff09; 一致性检查点&#xff08;che…

数据结构 | 查漏补缺之DFS、BFS、二次探测再散列法、完全二叉树、深度计算

目录 DFS&BFS 哈希表-二次探测再散列法 完全二叉树&深度计算 排序 快速排序-挖坑法 插入、选择、冒泡、区别 DFS&BFS 哈希表-二次探测再散列法 完全二叉树&深度计算 排序 快速排序-挖坑法 插入、选择、冒泡、区别 插入从第一个元素开始&#xff0c…

期末速成数据库极简版【存储过程】(5)

目录 【7】系统存储过程 【8】用户存储过程——带输出参数的存储过程 创建存储过程 存储过程调用 【9】用户存储过程——不带输出参数的存储过程 【7】系统存储过程 系统存储我们就不做过程讲解用户存储过程会考察一道大题&#xff0c;所以我们把重点放在用户存储过程。…

有一篇文章,共有3行文字,每行有80个字符。要求分别统计其中英文大写字母、小写字母、数字、空格以及其他字符的个数

目录 1解题思路&#xff1a; 2代码&#xff1a; 3运行代码&#xff1a; 4总结&#xff1a; 1解题思路&#xff1a; 有一篇文章&#xff0c;共有3行文字&#xff0c;每行有80个字符。要求分别统计其中英文大写字母、小写字母、数字、空格以及其他字符的个数 首先先设置一个字…