flutter pc端 使用grpc双向流

news2024/11/17 22:15:40

官网

grpc-dart:https://github.com/grpc/grpc-dart

proto文件

syntax = "proto3";

option go_package = "./";

package helloworld;

service RouteGuide {
  
  rpc GetFeature(Point) returns (Feature) {}

 
  rpc ListFeatures(Rectangle) returns (stream Feature) {}

  
  rpc RecordRoute(stream Point) returns (RouteSummary) {}

  
  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}


message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}

message Rectangle {

  Point lo = 1;


  Point hi = 2;
}


message Feature {

  string name = 1;


  Point location = 2;
}

message RouteNote {
.
  Point location = 1;

  // The message to be sent.
  string message = 2;
}


message RouteSummary {

  int32 point_count = 1;

  int32 feature_count = 2;


  int32 distance = 3;


  int32 elapsed_time = 4;
}

通过proto文件生成dart文件

命令
注意:笔者是先将protos文件夹放到根目录,再执行的这条命令
proto文件也是放在protos文件夹下面的
然后将操作后的peotos文件放到lib文件夹下

protoc --dart_out=grpc:protos -Iprotos protos/route_guide.proto

结果如下:
在这里插入图片描述

客户端实现

main.dart

import 'package:flutter/material.dart';
import 'package:app1/client.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, //去掉debug的标志
      title: "fltter Demo",
      theme: ThemeData(primaryColor: Color.fromRGBO(0, 137, 255, 1)),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () {
              () async {
                print("发送");
                List<String> args = [];
                await Client().main(args);
              }();
            },
            child: const Text("发送消息"),
          ),
        ],
      )),
    );
  }
}

common.dart

import 'dart:convert';
import 'dart:io';

import './protos/route_guide.pb.dart';

const coordFactor = 1e7;

final List<Feature> featuresDb = _readDatabase();

List<Feature> _readDatabase() {
  final dbData = File('data/route_guide_db.json').readAsStringSync();
  final List db = jsonDecode(dbData);
  return db.map((entry) {
    final location = Point()
      ..latitude = entry['location']['latitude']
      ..longitude = entry['location']['longitude'];
    return Feature()
      ..name = entry['name']
      ..location = location;
  }).toList();
}

client.dart

// Copyright (c) 2017, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import 'dart:math' show Random;

import 'package:grpc/grpc.dart';

import 'common.dart';
import 'protos/route_guide.pbgrpc.dart';

class Client {
  late RouteGuideClient stub;

  Future<void> main(List<String> args) async {
    final channel = ClientChannel('127.0.0.1',
        port: 8080,
        options:
            const ChannelOptions(credentials: ChannelCredentials.insecure()));
    stub = RouteGuideClient(channel,
        options: CallOptions(timeout: Duration(seconds: 30)));
    // Run all of the demos in order.
    try {
      await runRouteChat();
    } catch (e) {
      print('Caught error: $e');
    }
    await channel.shutdown();
  }

  void printFeature(Feature feature) {
    final latitude = feature.location.latitude;
    final longitude = feature.location.longitude;
    final name = feature.name.isEmpty
        ? 'no feature'
        : 'feature called "${feature.name}"';
    print(
        'Found $name at ${latitude / coordFactor}, ${longitude / coordFactor}');
  }

  /// Run the getFeature demo. Calls getFeature with a point known to have a
  /// feature and a point known not to have a feature.
  Future<void> runGetFeature() async {
    final point1 = Point()
      ..latitude = 409146138
      ..longitude = -746188906;
    final point2 = Point()
      ..latitude = 0
      ..longitude = 0;

    printFeature(await stub.getFeature(point1));
    printFeature(await stub.getFeature(point2));
  }

  /// Run the listFeatures demo. Calls listFeatures with a rectangle containing
  /// all of the features in the pre-generated database. Prints each response as
  /// it comes in.
  Future<void> runListFeatures() async {
    final lo = Point()
      ..latitude = 400000000
      ..longitude = -750000000;
    final hi = Point()
      ..latitude = 420000000
      ..longitude = -730000000;
    final rect = Rectangle()
      ..lo = lo
      ..hi = hi;

    print('Looking for features between 40, -75 and 42, -73');
    await for (var feature in stub.listFeatures(rect)) {
      printFeature(feature);
    }
  }

  /// Run the recordRoute demo. Sends several randomly chosen points from the
  /// pre-generated feature database with a variable delay in between. Prints
  /// the statistics when they are sent from the server.
  Future<void> runRecordRoute() async {
    Stream<Point> generateRoute(int count) async* {
      final random = Random();

      for (var i = 0; i < count; i++) {
        final point = featuresDb[random.nextInt(featuresDb.length)].location;
        print(
            'Visiting point ${point.latitude / coordFactor}, ${point.longitude / coordFactor}');
        yield point;
        await Future.delayed(Duration(milliseconds: 200 + random.nextInt(100)));
      }
    }

    final summary = await stub.recordRoute(generateRoute(10));
    print('Finished trip with ${summary.pointCount} points');
    print('Passed ${summary.featureCount} features');
    print('Travelled ${summary.distance} meters');
    print('It took ${summary.elapsedTime} seconds');
  }

  /// Run the routeChat demo. Send some chat messages, and print any chat
  /// messages that are sent from the server.
  Future<void> runRouteChat() async {
    RouteNote createNote(String message, int latitude, int longitude) {
      final location = Point()
        ..latitude = latitude
        ..longitude = longitude;
      return RouteNote()
        ..message = message
        ..location = location;
    }

    final notes = <RouteNote>[
      createNote('First message', 0, 0),
      createNote('Second message', 0, 1),
      createNote('Third message', 1, 0),
      createNote('Fourth message', 0, 0),
    ];

    Stream<RouteNote> outgoingNotes() async* {
      for (final note in notes) {
        // Short delay to simulate some other interaction.
        await Future.delayed(Duration(milliseconds: 10));
        print('Sending message ${note.message} at ${note.location.latitude}, '
            '${note.location.longitude}');
        yield note;
      }
    }

    final call = stub.routeChat(outgoingNotes());
    await for (var note in call) {
      print(
          'Got message ${note.message} at ${note.location.latitude}, ${note.location.longitude}');
    }
  }
}

服务端

服务端笔者使用的是go来开发的,所以只列出go语言的代码

proto文件

proto文件一定要与上文中提到的一致,否则会报错,错误码为code=12
这里不再赘述

通过proto文件生成go文件命令

注意:要将终端的路径切换到proto文件存在的文件目录下

在这里插入图片描述

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

server.go

package main

import (
	"fmt"
	"google.golang.org/grpc"
	pb "grpc_server/pbfiles"
	"log"
	"net"
	"sync"
	"time"
)

const (
	port = ":8080"
)

// 服务对象
type server struct {
	pb.UnimplementedRouteGuideServer
}

func (s *server) RouteChat(allStr pb.RouteGuide_RouteChatServer) error {
	fmt.Printf("1111")
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		for {
			data, _ := allStr.Recv()
			log.Println(data)
		}
	}()

	go func() {
		for {
			allStr.Send(&pb.RouteNote{
				Location: &pb.Point{
					Latitude:  1,
					Longitude: 1,
				},
				Message: "",
			})
			time.Sleep((time.Second))
		}
	}()

	wg.Wait()
	return nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		return
	}
	// 创建一个grpc 服务器
	s := grpc.NewServer()
	// 注册事件
	pb.RegisterRouteGuideServer(s, &server{})
	// 处理链接
	err = s.Serve(lis)
	if err != nil {
		return
	}
}

启动

先启动服务端,后启动客户端

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

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

相关文章

C#读写T5557芯片卡复制ID门禁卡源码

T5557卡是美国Atmel公司生产的多功能非接触式射频芯片卡&#xff0c;属于125KHz的低频卡&#xff0c;在国内有广大的应用市场&#xff0c;如很多酒店的门禁卡都是使用T5557卡。该芯片共有330bit(比特)的EPROM(分布为10个区块, 每个区块33bit)。0页的块0是被保留用于设置T5557操…

maven导入本地jar包

有些jar包是自己封装的或者来源公司私服等. 引入本地jar包方式 另外一种方式 包所在路径 cmd 这样jar包就在你仓库本地仓库里 然后导入

JVM-性能监控与调优-JVM运行时参数

JVM参数选项 官网地址&#xff1a;https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html 类型一&#xff1a;标准参数选项 > java -help 用法: java [-options] class [args...](执行类)或 java [-options] -jar jarfile [args...](执行 jar 文件) 其…

这都能第六?

文章目录&#x1f31f; 专栏介绍&#x1f31f; Vue默认版本&#x1f31f; 拥抱Vue3的UI&#x1f31f; Vue3显著优势&#x1f31f; 专栏介绍 凉哥作为 Vue 的忠诚粉丝输出过大量的 Vue 文章&#xff0c;应粉丝要求开始更新 Vue3 的相关技术文章&#xff0c;Vue 框架目前的地位大…

compooser remove移除包受版本约束导致失败

由于某个项目想移除某个扩展包&#xff0c;但一直报版本不兼容错导致移除不了。报错如下图。后面只要在移除包compooser语句后面加 --ignore-platform-reqs即可&#xff0c;命令&#xff1a;composer remove xxxxxx --ignore-platform-reqs。 移除扩展包后&#xff0c;执行php …

CnOpenData全国兴趣点(POI)数据

一、数据简介 POI&#xff08;Point of Interest&#xff09;&#xff0c;即兴趣点&#xff0c;一个POI可以是餐厅、超市、景点、酒店、车站、停车场等。兴趣点通常包含四方面信息&#xff0c;分别为名称、类别、坐标、分类。其中&#xff0c;分类一般有一级分类和二级分类&…

SpringBoot3x的服务间调用@HttpExchange

首先&#xff0c;我们之前曾经用过很多服务间调用的方式和方法&#xff0c;今天给大家介绍一款SpringBoot3x版本服务间调用&#xff0c;采用HttpExchange注解实现&#xff0c;方便快捷&#xff0c;简单易懂。 创建个SpringBoot3x项目 设置端口号为8081 import org.springframe…

开发日记-sublime3安装插件问题

由于notpad作者本人的一些个人错误观念&#xff0c;我对此软件产生极大恶意&#xff0c;所以又拾起了多年不用的sublime。sublime3其实是个非常好用的编辑器&#xff0c;有强大的插件扩展功能&#xff0c;但由于国内网络限制之前放弃了&#xff0c;这次研究明白了如何使用。 Pa…

谷歌公司再出大招,Chrome 新版本发布

导读您在用什么浏览器呢&#xff1f;Chrome 55 Beta 发布了&#xff0c;是不是很期待让我们一起来看看都有哪些方面的技术改进和变化呢&#xff1f;主要内容如下&#xff1a; 1、输入处理改进 随 着移动网络使用的普及&#xff0c;网站对触摸输入做出良好反应的重要性也日益增…

【内网安全】——meterpreter使用攻略

作者名&#xff1a;白昼安全主页面链接&#xff1a; 主页传送门创作初心&#xff1a; 一切为了她座右铭&#xff1a; 不要让时代的悲哀成为你的悲哀专研方向&#xff1a; web安全&#xff0c;后渗透技术每日emo&#xff1a; 再给我一年&#xff0c;好吗&#xff1f;Metasploit中…

点云的降采样

1. 点云深度学习中的新下采样方法 (CSDN) 现在比较常见的下采样算法有&#xff1a;farthest point sampling(PointNet&#xff0c;ShellNet)、random sampling(RandLA-Net)、grid sampling(KPConv&#xff0c;Grid-GCN)等。它们各有特点&#xff1a; farthest point sampling…

JUC并发编程之LinkedBlockingQueue的底层原理

作者简介&#xff1a;专注于研究Linux内核、Hotspot虚拟机、汇编语言、JDK源码、各大中间件源码等等喜欢的话&#xff0c;可以三连关注~LinkedBlockingQueue介绍在JUC包下关于线程安全的队列实现有很多&#xff0c;那么此篇文章讲解LinkedBlockingQueue的实现原理&#xff0c;相…

LeetCode 刷题系列 -- 1026. 节点与其祖先之间的最大差值

给定二叉树的根节点 root&#xff0c;找出存在于 不同 节点 A 和 B 之间的最大值 V&#xff0c;其中 V |A.val - B.val|&#xff0c;且 A 是 B 的祖先。&#xff08;如果 A 的任何子节点之一为 B&#xff0c;或者 A 的任何子节点是 B 的祖先&#xff0c;那么我们认为 A 是 B 的…

The Social Life of Autonomous Cars-自动驾驶汽车与日常生活

目录 自动驾驶汽车与日常生活 Abstract REPURPOSING ONLINE VIDEOS THE SOCIAL ROAD SEEING A GAP AS JUST A GAP SOMETIMES IT’S GOOD TO BE A CREEP THE UNCANNY VALLEY OF AUTONOMOUS CARS References 自动驾驶汽车与日常生活 作者Barry Brown时间06 February 201…

【智慧电力巡检】基于EasyCVR视频技术构建远程监控综合管理平台

一、方案背景电力行业和人民的生活、生产息息相关&#xff0c;一旦电力设施遭遇破坏或工作失误&#xff0c;就会造成大面积停电&#xff0c;其后果不堪设想&#xff0c;尤其是2003年美加“8.14”和2005年莫斯科“5.25”这两起大面积停电事故给我们敲响了警钟。随着电力行业的发…

zookeeper源码分享六 ---- 事物日志

二进制格式设计思想 在二进制格式设计中&#xff0c;其实和json的格式设计类似&#xff0c;也是有套路的。 设计要存储的内容(内容尽可能少&#xff0c;能用数字表示&#xff0c;不用字符串表示)。这些内容的前后顺序&#xff0c;读写都是按照这个顺序来的。 比如&#xff1…

来看看这几个办公技巧吧

技巧一&#xff1a;重复运行命令 当我们需要将一段中的不同单词加粗时&#xff0c;使用替换功能可能不是特别方便。这时可以使用万能的【F4】键进行重复操作。首先选中一个需要加粗的字&#xff0c;点击【加粗】设置完成字体的加粗&#xff1b;然后&#xff0c;选择另一个文本&…

1、python框架selenium

分层的自动化测试 什么样的产品适合做自动化测试&#xff1f; 功能成熟&#xff08;需求变动较小&#xff09; 产品更新维护周期长 项目进度不太大 比较频繁的回归测试 软件开发比较规范&#xff0c;具有可测试性 可以脚本具有可复用性 selenium 技术&#xff1a; 元素定位的…

[基础语法] python语法之列表、判断、循环例子

文章目录购物车案例已发布&#xff1a;整体框架打印商品列表将商品加入购物车打印购物车、计算总金额完整代码另外说明购物车案例 已发布&#xff1a; python判断语句python循环语句python之列表list购物车案例后续暂时不更新&#xff0c;有想要的部分&#xff0c;可以后台留…

11、Servlet——综合案例(Servlet+JDBC):管理员登录

目录 1、在MySQL中新建一个servletdatabase数据库&#xff0c;创建表admin 2、在web中创建登录页面login.html 3、在web中创建CSS文件夹&#xff0c;在CSS文件夹中创建login.css 4、在web下新建注册页面register.html 5、在CSS文件夹中新建register.css 6、在CSS文件夹下新…