[gRPC实现go调用go]

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服务端的服务

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Pytorch实现变分自编码器

使用Pytorch实现变分自编码器 可以结合这篇VAE讲解文章阅读这篇blog post代码。 # Import necessary packages. import os import torch import torch.nn as nn import torch.nn.functional as F import torchvision from torchvision import transforms from torchvision.ut…

微信小程序引入vant-weapp爬出坑

最新的微信小程序的项目结构跟之前的不一样,然后,按照vant-weapp上的官方文档,安装步骤失败,提示了各种错误。如果你的微信小程序结构跟我的一致,可以采用和我一样的方案。 微信小程序引入vant-weapp爬出坑 移动pack…

基于redisson实现发布订阅(多服务间用避坑)

前言 今天要分享的是基于Redisson实现信息发布与订阅(以前分享过直接基于redis的实现),如果你是在多服务间基于redisson做信息传递,并且有服务压根就收不到信息,那你一定要看完。 今天其实重点是避坑&#xff0…

TINA-TI —— 电路仿真

文章目录 1. 安装2. 1. 安装 Tina-TI 官网下载链接:https://www.ti.com.cn/tool/cn/TINA-TI注册登陆,选择简体中文版下载; 下载完成后,直接安装; 2.

Java最全面试题专题---1、Java基础知识(3)

IO流 java 中 IO 流分为几种? 按照流的流向分,可以分为输入流和输出流;按照操作单元划分,可以划分为字节流和字符流;按照流的角色划分为节点流和处理流。 Java Io流共涉及40多个类,这些类看上去很杂乱,…

Java安全之Commons Collections7分析

CC7分析 import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransfo…

spring-boot-starter-validation是什么Validation参数校验使用概要

spring-boot-starter-validation是什么&Validation参数校验使用概要 来源Valid和Validated的用法(区别)引入依赖Valid和Validated的用法 在日常的项目开发中,为了防止非法参数对业务造成的影响,需要对接口的参数做合法性校验,例如在创建用…

京东数据运营:京东API接口有哪些?京东数据如何采集调用?

市场分析对于电商品牌来说非常重要,它可以帮助电商品牌更好地理解市场,把握市场机会,以及制定有效的产品定价、产品营销策略等等。 结合市场中可以帮助品牌方做市场分析的电商数据分析工具——鲸参谋电商数据分析平台,我们一起具体…

快邀请你的冤种朋友一起来学习顺序表的底层逻辑:ArrayList集合

进来了就一起来学习如何去使用ArrayList这个集合吧! 目录 一.ArrayList是什么 二.ArrayList的构造方法与扩容机制 1.无参构造方法与扩容机制 2.带参数的构造方法 3.利用其他 Collection 构建 ArrayList 三.ArrayList常用方法介绍 1.插入数据方法 2.boolean …

react-photo-view 的介绍、安装、使用。

目录 基本介绍 安装 使用 基本介绍 react-photo-view 是一个基于 React 的图片查看器组件,用于在网页上展示和浏览图片。该组件提供了用户友好的界面和交互,可以轻松地在应用程序中集成并使用。 支持触摸手势,拖动/平移/物理效果滑动…

【vtkWidgetRepresentation】第七期 vtkImplicitPlaneRepresentation

很高兴在雪易的CSDN遇见你 前言 本文分享vtkImplicitPlaneRepresentation源码剖析,及相关的实例,该接口主要用于切割交互,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞关注,小易会继续努力分享,一起…

利用lammps模拟不同压头半径对单晶铝纳米压痕的影响

2.1.问题描述 纳米压痕是确定金属材料特性的最广泛使用的方法之一。分子动力学(MD)模拟是一种强大的工具,可以研究纳米压痕过程中原子尺度上的材料行为,并深入了解材料的塑性变形。本工作采用单晶铝作为原材料,旨在为…

虾皮免费分析工具:了解市场趋势、优化产品和店铺运营

在如今竞争激烈的电商市场中,了解市场趋势、优化产品和店铺运营对于卖家来说至关重要。虾皮(Shopee)作为一家知名的电商平台,为卖家提供了一些免费的分析工具,帮助他们更好地了解市场情况并做出明智的决策。本文将介绍…

人工智能教程(三):更多有用的 Python 库

目录 前言 推荐 JupyterLab 入门 复杂的矩阵运算 其它人工智能和机器学习的 Python 库 前言 在本系列的上一篇人工智能教程(二):人工智能的历史以及再探矩阵中,我们回顾了人工智能的历史,然后详细地讨论了矩阵。在…

导入PR的视频画面是黑屏的怎么办?

在现代视频编辑领域中,越来越多的人使用Adobe Premiere Pro来编辑和制作视频,但是在某些情况下,用户可能需要透明背景的视频进行创作,那么如何创作透明背景的视频呢? 要制作具有透明背景的视频,我们需要使…

深度探索Linux操作系统 —— 构建initramfs

系列文章目录 深度探索Linux操作系统 —— 编译过程分析 深度探索Linux操作系统 —— 构建工具链 深度探索Linux操作系统 —— 构建内核 深度探索Linux操作系统 —— 构建initramfs 文章目录 系列文章目录前言一、为什么需要 initramfs二、initramfs原理探讨三、构建基本的init…

在Windows 11中,至少有四种方法可以创建用户

本文介绍如何在Windows11上添加另一个用户(或多个用户)。 使用设置添加其他用户 这是创建新用户的“正常”方式。这是一个简单的过程,允许你添加Microsoft、本地或家庭帐户。 添加Microsoft或本地帐户 按照以下步骤将Microsoft帐户添加到Windows 11或创建新的本地用户。…

论文阅读:PointCLIP: Point Cloud Understanding by CLIP

CVPR2022 链接:https://arxiv.org/pdf/2112.02413.pdf 0、Abstract 最近,通过对比视觉语言预训练(CLIP)的零镜头学习和少镜头学习在2D视觉识别方面表现出了鼓舞人心的表现,即学习在开放词汇设置下将图像与相应的文本匹配。然而,…

实现手机扫码——扫描识别路由器参数

有个应用是批量自动检测无线路由器,检测前需要自动登录路由器的管理界面进行设置,如设置wifi参数、连接模式,或者恢复出厂设置等。进入管理界面的登录用户名是admin,密码则各不相同。此外也需要知道路由器的MAC地址,因…

Qt基础-程序打包发布方法

本文讲解Qt程序打包发布方法。 一、使用Qt自带的windeployqt 生成可运行的包 准备将Qt生成的exe拷入到单独的文件夹,并进行命名,本文命名为packDemorun,并将文件放到D盘(自己随意放置) 1、找到Qt自带的命令终端 2、启动命令终端 3、输入:cd /d D:\packDemorun,进入文…