gRpc_go_dart-1.编写第一个服务

通俗的讲下grpc

简化掉所有复杂的实现,它要求服务端和客户端之间按照protobuf的规范进行数据交换,所以服务端和客户端都不用关心彼此的代码实现,只关心按照protobuf的形式提供数据

为什么是go和dart

技术栈,已经是google的形状了

同时,go客户端和Flutter间本身通过http协议不好交接数据,用grpc更快更方便

Hello,World

这个章节将教会你实现用go编写服务端提供grpc接口,而在flutter中定义一个按钮和输入框输入姓名来请求go服务端并获取信息

核心的规范文件-protobuf-及基于go的grpc服务端实现

  1. protobuf是grpc中最重要的文件,它规定了服务端与客户端之间通信的规范,同时我们也要求客户端和服务端中的protobuf文件必须完全一致,所以让我们首先来编写这个protobuf文件,让我们思考一下这个pro文件要实现什么功能

  2. 它应当有一个服务获取请求的字符后返回Hello world + name 字符串

  3. 我们首先编写人类可读的proto文件,这个文件是人类可以阅读的:

  4. syntax = "proto3";
    //指定了 Go 语言代码生成后应该放置在名为 "github.com/rn-consider/grpcservice/helloworld" 的包中,
    //会影响生成的 .pb.go 文件的 package 声明
    option go_package = "github.com/rn-consider/grpcservice/helloworld";
    option java_multiple_files = true;
    option java_package = "io.helloworld.examples.helloworld";
    option java_outer_classname = "HelloWorldProto";package helloworld;// 此处定义服务,为协议缓冲区中的服务定义
    service Greeter {/*提供SayHello函数,接受HelloRequest类型的消息,返回HelloReply类型的消息在grpc中,函数必须始终具有输入消息并返回输出消息*/// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {}// Sends another greetingrpc SayHelloAgain (HelloRequest) returns (HelloReply) {}}// 要求传入参数必须要name
    message HelloRequest {/*字段的设计十分重要,应谨慎分配字段编号,切勿更改,且在设计时考虑未来的修订消息中的字段定义必须指定三件事:类型,名称,编号字段的类型可以是当前支持的整数类型(int32,int64等),float,double,bool,字符串,字节(用于任何数据)要注意的是字段名称必须全部小写,并使用_分隔多个单词.如first_name,字段编号表示字段在消息中的位置,如name = 1表示name在返回信息中占第一位字段编号可以从1到2^29推荐在字段编号内留下间距,例如将第一个字段编号为1,然后将10用于下一个字段这意味着可在稍后添加任何其他字段而不需要对字段进行编号*/string name = 1;
    }// 要求返回参数必须要是message
    message HelloReply {string message = 1;
    }
    
  5. 然后我们使用proto工具将这个人类proto转化为用于客户端和服务端定义的接口文件.我们永远不会手动编辑这些文件:

  6. protoc --go_out=. --go_opt=paths=source_relative \--go-grpc_out=. --go-grpc_opt=paths=source_relative \helloworld/helloworld.proto
    
  7. windows下执行:

  8. protoc --go_out=. --go_opt=paths=source_relative "--go-grpc_out=." "--go-grpc_opt=paths=source_relative" helloworld\helloworld.proto
    
  9. 获得如下的文件,现在项目结构应该如:

  10. Image1

  11. 接下来我们在main函数中导入,并实现在pb中定义的函数

  12. // Package main implements a server for Greeter service.
    package mainimport ("context""log""net"pb "github.com/rn-consider/grpcservice/helloworld""google.golang.org/grpc"
    )// server 用来实现pb中的helloworld.GreeterServer.
    type server struct {pb.UnimplementedGreeterServer
    }// SayHello 实现helloworld.GreeterServer
    func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {log.Printf("Received: %v", in.GetName())return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
    }func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {return &pb.HelloReply{Message: "Hello again " + in.GetName()}, nil
    }func main() {// grpc服务默认应该运行在50051端口lis, err := net.Listen("tcp", ":50051")if err != nil {log.Fatalf("报错: %v", err)}s := grpc.NewServer()// 注册服务pb.RegisterGreeterServer(s, &server{})log.Printf("server listening at %v", lis.Addr())if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
    }
    

当看到输出时,说明gRpc的服务端已经运行成功

基于go服务端中的protobuf文件实现dart客户端

注意:环境要求安装dart-sdk或者flutter

当我们想要使用dart快速创建一个项目,因为我们要创建供flutter使用的客户端,使用

dart项目命名规范要求全部小写,用_来分隔单词,建议直接全小写了,dart是很严格的语言

dart create -t package helloworld

删掉不必要的文件并增加存放protos和其编译后文件的项目结构应该如

  • 编辑我们把go服务端写好的proto文件复制到protos目录下,往

  • pubspec.yaml里添加依赖,:后不加版本号默认获取最新:

  • dependencies:# path: ^1.8.0async: ^2.2.0grpc: ^3.2.4protobuf: ^3.0.0dev_dependencies:lints: ^2.0.0test: ^1.21.0
    
  • 然后运行:

  • protoc --dart_out=grpc:lib/src/generated -Iprotos protos/helloworld.proto

  • 接下来我们在bin中增加client.dart文件,我们将在其中实现grpc客户端,删除不必要的文件后项目结构应该如:

  • 接下来我们在dart.client里添加代码

  • import 'package:grpc/grpc.dart';
    import 'package:helloworld/src/generated/helloworld.pbgrpc.dart';class GreeterService {late ClientChannel _channel;late GreeterClient _stub;GreeterService(String host, int port) {_channel = ClientChannel(host,port: port,options: ChannelOptions(credentials: ChannelCredentials.insecure(),),);_stub = GreeterClient(_channel);}Future<String> callSayHello(String name) async {try {final response = await _stub.sayHello(HelloRequest()..name = name,);return response.message;} catch (e) {print('Caught error: $e');return 'Error occurred';} finally {await _channel.shutdown();}}
    }
    

运行了go service后我们可以新建测试目录测试dart clilent

并在test/client_test.dart中加入以下代码:

import 'package:test/test.dart';
import 'package:helloworld/bin/client.dart'; // 根据实际路径进行调整void main() {group('GreeterService', () {late GreeterService greeterService;setUp(() {greeterService = GreeterService('localhost',50051);});test('callSayHello returns correct message', () async {final name = 'John';final result = await greeterService.callSayHello(name);expect(result, 'Hello $name');});test('callSayHello handles error', () async {final name = 'Error';final result = await greeterService.callSayHello(name);expect(result, 'Hello Error');});});
}

可看见测试通过:

将上一步的dart客户端整合为Packages

因为我们一开始就是基于Package创建的项目所以现在只需要在lib目录下创建与项目同名的dart文件,在这里我们导出bin/client中的GreeterService:

Image2

然后新建flutter项目并且按照顺序

更改pubspec.yaml中的依赖项我们让它能索引到本地包

在lib/main.dart中添加以下代码

flutter调用dart客户端

    • 首先新建一flutter项目,初始的flutter项目结构如:

    • 我们的源代码应该放在lib目录中:

    • 让我们在main.dart中调用它:

    • import 'package:flutter/material.dart';
      import 'package:helloworld/helloworld.dart'; // 根据实际路径进行调整void main() {runApp(MyApp());
      }class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {final greeterService = GreeterService('localhost',50051);return MaterialApp(title: 'Flutter gRPC Example',home: MyHomePage(greeterService: greeterService),);}
      }class MyHomePage extends StatefulWidget {final GreeterService greeterService;MyHomePage({required this.greeterService});@override_MyHomePageState createState() => _MyHomePageState();
      }class _MyHomePageState extends State<MyHomePage> {final TextEditingController _nameController = TextEditingController();String _message = '';@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Flutter gRPC Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Padding(padding: EdgeInsets.all(16.0),child: TextField(controller: _nameController,decoration: InputDecoration(labelText: 'Enter your name'),),),ElevatedButton(onPressed: () async {final name = _nameController.text;final response = await widget.greeterService.callSayHello(name);setState(() {_message = response;});},child: Text('Call gRPC Service'),),SizedBox(height: 20.0),Text('Response: $_message',style: TextStyle(fontSize: 18.0),),],),),);}@overridevoid dispose() {_nameController.dispose();super.dispose();}
      }
      

      编译后你便能看到运行的结果,我们的windows桌面应用已经可以获取grpc响应,假如说我们想在移动端使用呢?这需要一台有公网ip的服务器,并在实例化GreeterService时传入服务器的主机名:

在安卓中使用

  1. 先编译go service为linux可执行文件,我使用的linux架构为amd64,

  2. 注意修改main.go中的监听地址,还有注意在服务器运营商的安全组开放50051端口,还有注意关闭服务器的防火墙

  3. 结果如

  4. 上传服务器并运行,用nohup使其后台运行

  5. 更改flutter的实例化

  6. Image3

成功

额外讲点:生成的pb文件的作用

  1. helloworld.pb.go

    • 这个文件包含了与消息定义相关的代码。每个在 helloworld.proto 中定义的消息类型(如 HelloRequestHelloResponse)都会对应生成 Go 结构体,并且这些结构体实现了 Protocol Buffers 的序列化和反序列化方法,以便在网络上传输或进行持久化时使用。
    • 此文件还包含了一些辅助方法,用于创建、解析和操作消息对象。这些方法让你能够更轻松地使用消息类型。
  2. helloworld_grpc.pb.go

    • 这个文件包含了与 gRPC 服务定义相关的代码。在 helloworld.proto 中定义的 gRPC 服务(如 Greeter)会被转化为 Go 接口,并且为每个 gRPC 方法生成相应的客户端和服务器端函数。
    • 客户端函数用于向远程 gRPC 服务发起请求,而服务器端函数用于处理客户端请求并返回响应。

额外讲点:dart create命令详解

Dart 官方提供了多种不同类型的模板,以满足不同类型的项目需求。一些常见的 Dart 模板包括:

  • console:用于创建命令行应用程序的模板
  • web:用于创建 Web 应用程序的模板。
  • package:用于创建 Dart 软件包库的模板,供其他 Dart 项目使用。
  • server:用于创建 Dart 服务器应用程序的模板,用于构建服务器端应用程序。

额外讲点:dart proto生成pb文件命令详解

protoc --dart_out=grpc:lib/src/generated -Iprotos protos/helloworld.proto

  • protoc 是 Protocol Buffers 编译器。
  • --dart_out=grpc:lib/src 指定生成的 Dart 代码应放置在 lib/src/generated 目录中,并包括 gRPC 支持。
  • -Iprotos 指定搜索 Proto 文件的路径(protos 目录)。
  • protos/helloworld.proto 是您要生成 Dart 代码的 Proto 文件的路径。
    创建 Dart 软件包库的模板,供其他 Dart 项目使用。
  • server:用于创建 Dart 服务器应用程序的模板,用于构建服务器端应用程序。

额外讲点:dart proto生成pb文件命令详解

protoc --dart_out=grpc:lib/src/generated -Iprotos protos/helloworld.proto

  • protoc 是 Protocol Buffers 编译器。
  • --dart_out=grpc:lib/src 指定生成的 Dart 代码应放置在 lib/src/generated 目录中,并包括 gRPC 支持。
  • -Iprotos 指定搜索 Proto 文件的路径(protos 目录)。
  • protos/helloworld.proto 是您要生成 Dart 代码的 Proto 文件的路径。

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

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

相关文章

Java(运算符+循环)万字超详细介绍 (囊括了按位,异或,for,while等基础和疑难知识)

【本节目标1】熟练掌握运算符 【本章目标2】熟练掌握循环 万字讲解&#xff0c;十分详细&#xff0c;有大量&#xff08;简单&#xff09;代码帮助理解和大量的&#xff08;简单&#xff09;举例与总结。 1.运算符 1.什么是运算符 计算机最基本的用途之一就是执行数学运算…

如何实现一个简单的Promise/A+规范的Promise库?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Promise/A规范的Promise⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚…

ROS2-IRON Ubuntu-22.0 源码下载失败解决方法 vcs import --input

ROS2 一.ROS2 IRON环境搭建1.设置系统字符集为UTF-82.将RO2 apt 库添加到系统中3.添加ROS2 GPG key4.添加ROS 2 的软件源安装开发工具 二.下载ROS2sh源代码编译 一.ROS2 IRON环境搭建 虚拟机系统&#xff1a;Ubuntu22.04 虚拟机&#xff1a;VMware-player-full-16.2.5-2090451…

身份和访问管理解决方案:混合型IAM

对于依赖于本地 IT 基础结构和传统安全模型的组织&#xff0c;可以更轻松地验证和授权企业网络内的所有内容&#xff0c;包括设备、用户、应用程序和服务器。尝试从公司网络外部获取访问权限的用户使用虚拟专用网络 &#xff08;VPN&#xff09; 和网络访问控制 &#xff08;NA…

【Spring Boot系列】- Spring Boot侦听器Listener

【Spring Boot系列】- Spring Boot侦听器Listener 文章目录 【Spring Boot系列】- Spring Boot侦听器Listener一、概述二、监听器Listener分类2.1 监听ServletContext的事件监听器2.2 监听HttpSeesion的事件监听器2.3 监听ServletRequest的事件监听器 三、SpringMVC中的监听器3…

匿名管道-

因为父子进程是共享文件描述符的环形队列&#xff0c;只能读一次 会被后面覆盖 /*#include <unistd.h>int pipe(int pipefd[2]);功能&#xff1a;创建一个匿名管道&#xff0c;用于进程间通信参数&#xff1a;int 类型数组 &#xff0c;是传出参数pipefd[0]是管道读端 p…

Git多人开发解决冲突案例

准备工作&#xff1a; 1.创建一个gitee远程仓库https://gitee.com/xxxxxxx.git 2.初始化两个本地git仓库用户&#xff0c;目的是模拟多人协作开发时提交代码发生冲突的场景 3.解决冲突并提交。 进入正题&#xff1a; lisi 通过vim指令修改readme.md文件内容&#xff0c;推送到…

Centos8系统中安装docker-compose报错(已解决)

1.报错内容&#xff1a; ModuleNotFoundError: No module named setuptools_rust Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-jrzp2ukw/bcrypt/2.报错原因&#xff1a; 在CentOS8中安装“加密”程序包时出现问题。当包所需的…

Windows关闭zookeeper、rocketmq日志输出以及修改rocketmq的JVM内存占用大小

JDK-1.8zookeeper-3.4.14rocketmq-3.2.6 zookeeper 进入到zookeeper的conf目录 清空配置文件&#xff0c;只保留下面这一行。zookeeper关闭日志输出相对简单。 log4j.rootLoggerOFFrocketmq 进入到rocketmq的conf目录 logback_broker.xml <?xml version"1.0&q…

SpringMVC中的JSR303与拦截器的使用

一&#xff0c;JSR303的概念 JSR303是Java中的一个标准&#xff0c;用于验证和校验JavaBean对象的属性的合法性。它提供了一组用于定义验证规则的注解&#xff0c;如NotNull、Min、Max等。在Spring MVC中&#xff0c;可以使用JSR303注解对请求参数进行校验。 1.2 为什么要使用J…

深度学习-卷积神经网络-纹理表示卷积神经网络-卷积神经网络-[北邮鲁鹏]

这里写目录标题 参考文章全连接神经网络全连接神经网络的瓶颈全连接神经网络应用场景 卷积神经网络卷积层(CONV)卷积核卷积操作卷积层设计卷积步长(stride)边界填充特征响应图组尺寸计算 激活层池化层(POOL)池化操作定义池化操作作用池化层超参数常见池化操作 全连接层(FC)样本…

【看好了】如何使用fiddler实现手机抓包,Filters过滤器!

一、Fiddler与其他抓包工具的区别  1、Firebug虽然可以抓包&#xff0c;但是对于分析http请求的详细信息&#xff0c;不够强大。模拟http请求的功能也不够&#xff0c;且firebug常常是需要“无刷新修改”&#xff0c;如果刷新了页面&#xff0c;所有的修改都不会保存&#xff…

文安县人社局 举办“情暖灾区 就业护航”直播带岗活动

关于防汛救灾工作重要指示精神&#xff0c;助力受灾企业尽快复工复产、受灾群众尽早实现就业。9月15日&#xff0c;文安县人力资源和社会保障局联合文安县总工会、国家税务总局文安县税务局共同举办文安县助力企业灾后重建“直播带岗”活动。 本次活动以“情暖灾区 就业护航”…

IDEA中DEBUG技巧

Debug 介绍 Debug 设置 如上图标注 1 所示&#xff0c;表示设置 Debug 连接方式&#xff0c;默认是 Socket。Shared memory 是 Windows 特有的一个属性&#xff0c;一般在 Windows 系统下建议使用此设置&#xff0c;相对于 Socket 会快点。 ## Debug 常用快捷键 Win 快捷键M…

分享一个Python 写的监控日志log txt文档 的代码

监控log文件的需求 某些特殊原因&#xff0c;想一直看到.log 的最后一行打印&#xff0c;所以写了一些代码监控log &#xff08;有个奇怪需求&#xff0c;就是log 因为重复启动原因&#xff0c;会一直加&#xff0c;不是同一个log&#xff09; 监控界面 涉及的Python代码&…

Unity SteamVR 开发教程:用摇杆/触摸板控制人物持续移动(2.x 以上版本)

文章目录 &#x1f4d5;教程说明&#x1f4d5;场景搭建&#x1f4d5;创建移动的动作&#x1f4d5;移动脚本⭐移动⭐实时调整 CharacterController 的高度 &#x1f4d5;取消手部和 CharacterController 的碰撞 持续移动是 VR 开发中的一个常用功能。一般是用户推动手柄摇杆&…

CNN(八):Inception V1算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 1 Inception V1 Inception v1论文 1.1 理论知识 GoogLeNet首次出现在2014年ILSVRC比赛中获得冠军。这次的版本通常称其为Inception V1。…

strncpy

strncpy&#xff1a; 函数介绍&#xff1a; 函数原型&#xff1a; char *strncpy(char *dest, const char *src, int n) 返回值&#xff1a;dest字符串起始地址 说明&#xff1a; 1、当src字符串长度小于n时&#xff0c;则拷贝完字符串后&#xff0c;剩余部分将用空字节填…

建站系列(八)--- 本地开发环境搭建(WNMP)

目录 相关系列文章前言一、准备工作二、Nginx安装三、MySQL安装四、PHP安装及Nginx配置五、总结 相关系列文章 建站系列&#xff08;一&#xff09;— 网站基本常识 建站系列&#xff08;二&#xff09;— 域名、IP地址、URL、端口详解 建站系列&#xff08;三&#xff09;— …

【设计模式】二、UML 类图概述

文章目录 常见含义含义依赖关系&#xff08;Dependence&#xff09;泛化关系&#xff08;Generalization&#xff09;实现关系&#xff08;Implementation&#xff09;关联关系&#xff08;Association&#xff09;聚合关系&#xff08;Aggregation&#xff09;组合关系&#x…