广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Go语言学习otns示例分析
  • 548
分享到

Go语言学习otns示例分析

Go语言otns示例Go otns分析 2023-05-17 08:05:08 548人浏览 薄情痞子
摘要

目录学习过程proto文件visualize/grpc/replay目录下的文件cmd/otns-replay目录下的文件grpc_Service(包含pb)otns_replay(

学习过程

由于在用虚拟机体验过程中出现了未知的错误之后,打算使用wsl又遇到了安装错误,各种办法解决无果,于是我打算跳过体验的这一部分,直接先进行这个例子中的grpc调用部分的梳理分析,等有空了再去解决一下wsl安装不了的问题。

proto文件

这个例子中只有一个proto文件,位于ot-ns-main/visualize/grpc/pb下,里面的service也只定义了两个rpc方法:

service VisualizeGrpcService {
    //    rpc Echo (EchoRequest) returns (EchoResponse);
    rpc Visualize (VisualizeRequest) returns (stream VisualizeEvent);
    rpc Command (CommandRequest) returns (CommandResponse);
}
  • Visualize (VisualizeRequest) returns (stream VisualizeEvent)

这个方法接受一个VisualizeRequest,返回VisualizeEvent流。两个消息定义如下:

message VisualizeRequest {
}
message VisualizeEvent {
    oneof type {
        AddnodeEvent add_node = 1;
        DeleteNodeEvent delete_node = 2;
        SetNodeRloc16Event set_node_rloc16 = 3;
        SetNodeRoleEvent set_node_role = 4;
        SetNodePosEvent set_node_pos = 5;
        SetNodePartitionIdEvent set_node_partition_id = 6;
        OnNodeFailEvent on_node_fail = 7;
        OnNodeRecoverEvent on_node_recover = 8;
        SetParentEvent set_parent = 9;
        CountDownEvent count_down = 10;
        ShowDemoLegendEvent show_demo_legend = 11;
        AdvanceTimeEvent advance_time = 12;
        AddRouterTableEvent add_router_table = 13;
        RemoveRouterTableEvent remove_router_table = 14;
        AddChildTableEvent add_child_table = 15;
        RemoveChildTableEvent remove_child_table = 16;
        SendEvent send = 17;
        SetSpeedEvent set_speed = 18;
        HeartbeatEvent heartbeat = 19;
        OnExtAddrChangeEvent on_ext_addr_change = 20;
        SetTitleEvent set_title = 21;
        SetNodeModeEvent set_node_mode = 22;
        SetNetworkInfoEvent set_network_info = 23;
    }
}

请求为空,而VisualizeEvent里面使用oneof关键字包含了很多的消息体,每个消息体封装了一个事件。

  • Command (CommandRequest) returns (CommandResponse)

这个方法接受CommandRequest并返回CommandResponse,两个消息体定义如下:

message CommandRequest {
    string command = 1;
}
message CommandResponse {
    repeated string output = 1;
}

CommandResponse中的output在go中会声明为string[]

visualize/grpc/replay目录下的文件

  • grpcField(未包含pb)

定义了一个结构grpcField,里面包含了节点信息、当前时间与速度、标题信息、网络信息、及其设置。

type grpcField struct {
   nodes       map[NodeId]*grpcNode
   curTime     uint64
   curSpeed    float64
   speed       float64
   titleInfo   visualize.TitleInfo
   networkInfo visualize.networkInfo
}
  • grpcNode(未包含pb)

定义了节点结构grpcNode,包含各种信息,还有一个new这个结构的函数

type grpcNode struct {
   nodeid      NodeId
   extaddr     uint64
   x           int
   y           int
   radioRange  int
   mode        NodeMode
   rloc16      uint16
   role        OtDeviceRole
   partitionId uint32
   failed      bool
   parent      uint64
   routerTable map[uint64]struct{}
   childTable  map[uint64]struct{}
}
  • grpcServer(包含pb)

自定义了一个grpcServer,包含信息如下

type grpcServer struct {
   vis                *grpcVisualizer
   server             *grpc.Server
   address            string
   visualizingStreams map[*grpcStream]struct{}
}

同时按照接口要求实现了Visualize()Command()方法,还自定义了其他的方法如runstopprepareStream等等,看名字就容易知道是什么用途

  • grpcStream(包含pb)

里面自定义了一个结构grpcStream,使用这个文件中的newGrpcStream可以将Visualize函数的服务端流赋到这个结构中

  • grpcVisualizer(包含pb)

其中自定义了一个结构:

    type grpcVisualizer struct {
       simctrl             visualize.SimulationController
       server              *grpcServer
       f                   *grpcField
       showDemoLegendEvent *pb.VisualizeEvent
       replay              *replay.Replay
       sync.Mutex
    }
  • 需要注意的是这个结构继承了互斥sync.Mutex,并且包含了上面的grpcServer、grpcServer结构,这个文件里面的函数大概都是添加、删除节点或者修改什么信息之类的,基本是调用了grpcFieldgrpcServer文件里面的函数,但是在调用之前加了锁。
  • 这个结构实现了visualize/types.go中的Visualizer接口
  • 并且,这个结构中包含了visualize.SimulationController接口的字段,而visualize.SimulationController定义如下:
type SimulationController interface {
    Command(cmd string) ([]string, error)
}

大概就是命令的入口。

cmd/otns-replay目录下的文件

grpc_Service(包含pb)

  • 定义了grpcService结构,并且实现了VisualizeCommand两个方法
type grpcService struct {
   replayFile string
}

2. grpcService结构下的visualizeStream()函数

grpcService的replay文件检验并打开,并且逐行读取内容,并解析到var entry pb.ReplayEntry中,再通过stream将entry.Event发送到服务的客户端

  • 实现的Visualize方法:

启动visualizeStream()协程,创建一个心跳事件,每隔一秒心跳一下,直到上面的visualizeStream()读取完成

otns_replay(包含pb)

main()函数

一系列的校验和配置参数之后,用上面的grpcService结构注册服务端,在本机地址8999端口监听。然后就是配置和打开网页

cmd/otns/otns.go文件

调用了otns_main/otns_main.go下的Main()函数:

首先依然是解析和配置参数和环境:

parseArgs()
simplelogger.SetLevel(simplelogger.ParseLevel(args.LogLevel))
parseListenAddr()
rand.Seed(time.Now().UnixNano())
// run console in the main goroutine
ctx.Defer(func() {
   _ = os.Stdin.Close()
})
handleSignals(ctx)

然后是打开replay文件并创建visualizer实例:

var vis visualize.Visualizer
if visualizerCreator != nil {
   vis = visualizerCreator(ctx, &args)
}
visGrpcServerAddr := fmt.Sprintf("%s:%d", args.DispatcherHost, args.DispatcherPort-1)
replayFn := ""
if !args.NoReplay {
   replayFn = fmt.Sprintf("otns_%s.replay", os.Getenv("PORT_OFFSET"))
}
if vis != nil {
   vis = visualizeMulti.NewMultiVisualizer(
      vis,
      visualizeGrpc.NewGrpcVisualizer(visGrpcServerAddr, replayFn),
   )
} else {
   vis = visualizeGrpc.NewGrpcVisualizer(visGrpcServerAddr, replayFn)
}

创建一个新模拟,并设置CmdRunnerVisualizer

sim := createSimulation(ctx)
rt := cli.NewCmdRunner(ctx, sim)
sim.SetVisualizer(vis)

启动一个协程运行模拟:

go sim.Run()

启动客户命令行协程:

go func() {
   err := cli.Run(rt, cliOptions)
   ctx.Cancel(errors.Wrapf(err, "console exit"))
}()

设置并打开网页:

go func() {
   siteAddr := fmt.Sprintf("%s:%d", args.DispatcherHost, args.DispatcherPort-3)
   err := WEBSite.Serve(siteAddr)
   if err != nil {
      simplelogger.Errorf("site quited: %+v, OTNS-Web won't be available!", err)
   }
}()
if args.AutoGo {
   go autoGo(ctx, sim)
}
web.ConfigWeb(args.DispatcherHost, args.DispatcherPort-2, args.DispatcherPort-1, args.DispatcherPort-3)
simplelogger.Debugf("open web: %v", args.OpenWeb)
if args.OpenWeb {
   _ = web.OpenWeb(ctx)
}

Visualizer启动:

vis.Run() // visualize must run in the main thread

simulation目录下的文件

simulationgrpcVisualizercmdRunner通信的桥梁。

type.go

定义了CmdRunner接口:

type CmdRunner interface {
   RunCommand(cmd string, output io.Writer) error
}

simulationController.go

  • 定义了simulationController类,这个类实现了visualize.SimulationController接口,也就是grpcVisualizer里有的字段:
type simulationController struct {
   sim *Simulation
}
func (sc *simulationController) Command(cmd string) ([]string, error) {
   var outputBuilder strings.Builder
   sim := sc.sim
   err := sim.cmdRunner.RunCommand(cmd, &outputBuilder)
   if err != nil {
      return nil, err
   }
   output := strings.Split(outputBuilder.String(), "\n")
   if output[len(output)-1] == "" {
      output = output[:len(output)-1]
   }
   return output, nil
}
  • 还定义了同样实现了visualize.SimulationController接口的只读类,这里不展开说了。
  • 还有一个NewSimulationController(sim *Simulation)函数产生simulationController
  • simulationController应该是一个介于Command和Simulation之间的中介,接收Command并操作CmdRunner更改Simulation,并且输出信息。

simulation_config.go

定义了配置和默认配置

simulation.go

  • simulation结构定义:
type Simulation struct {
   ctx         *proGCtx.ProgCtx
   cfg         *Config
   nodes       map[NodeId]*Node
   d           *dispatcher.Dispatcher
   vis         visualize.Visualizer
   cmdRunner   CmdRunner
   rawMode     bool
   networkInfo visualize.NetworkInfo
}
  • 有一个new产生simulation结构的函数
  • 各种增删改查操作,都是通过simulation结构中的visualize.Visualizer接口函数实现的

cli目录

cli目录下定义了CmdRunner及各种指令结构

ast.go

定义了各种命令结构

CmdRunner.go

  • 定义了CmdRunner结构:
type CmdRunner struct {
   sim           *simulation.Simulation
   ctx           *progctx.ProgCtx
   contextNodeId NodeId
}
  • 实现simulation/CmdRunner接口的RunCommand方法:
func (rt *CmdRunner) RunCommand(cmdline string, output io.Writer) error {
   // run the OTNS-CLI command without node contexts
   cmd := Command{}
   if err := ParseBytes([]byte(cmdline), &cmd); err != nil {
      if _, err := fmt.Fprintf(output, "Error: %v\n", err); err != nil {
         return err
      }
   } else {
      rt.execute(&cmd, output)
   }
   return nil
}
  • RunCommand方法中解析配置好命令后,有各种execute...()函数来执行相应的命令,而在这些函数中又是通过调用simulation.Simulation中对应的增删改查函数来实现操作的

总结

以上就是Go语言学习otns示例分析的详细内容,更多关于Go语言otns示例的资料请关注编程网其它相关文章!

您可能感兴趣的文档:

--结束END--

本文标题: Go语言学习otns示例分析

本文链接: https://www.lsjlt.com/news/210972.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Go语言学习otns示例分析
    目录学习过程proto文件visualize/grpc/replay目录下的文件cmd/otns-replay目录下的文件grpc_Service(包含pb)otns_replay(...
    99+
    2023-05-17
    Go语言otns示例 Go otns分析
  • Go语言结构的示例分析
    这篇文章主要为大家展示了“Go语言结构的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Go语言结构的示例分析”这篇文章吧。当前的调试部分可以使用 go run filename.go 来...
    99+
    2023-06-20
  • Golang语言学习拿捏Go反射示例教程
    目录1. 反射简介1.1 反射是什么?1.2 为什么需要反射?2. reflect包2.1 基本反射2.2 反射与指针2.3 反射与对象2.4 反射与函数2.5 反射例子3. 总结1...
    99+
    2022-11-12
  • Go语言基础学习之map的示例详解
    目录Mapmap定义map基本使用判断某个键是否存在map的遍历使用delete()函数删除键值对按照指定顺序遍历map元素为map类型的切片值为切片类型的mapMap实现原理什么是...
    99+
    2023-05-14
    Golang map原理 Golang map实现 Golang map
  • Go语言使用指针的示例分析
    这篇文章给大家分享的是有关Go语言使用指针的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。普通指针和C语言一样, 允许用一个变量来存放其它变量的地址, 这种专门用于存储其它变量地址的变量, 我们称之为指针...
    99+
    2023-06-20
  • Go语言异常处理的示例分析
    这篇文章主要为大家展示了“Go语言异常处理的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Go语言异常处理的示例分析”这篇文章吧。异常处理程序运行时,发生的不被期望的事件,它阻止了程序按...
    99+
    2023-06-20
  • Go语言中通道channel的示例分析
    这篇文章将为大家详细讲解有关Go语言中通道channel的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、Go语言通道基础概念1.channel产生背景    线程...
    99+
    2023-06-29
  • Go语言单元测试的示例分析
    小编给大家分享一下Go语言单元测试的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、单元测试分类及其概念1.基本分类测试函数 函数前缀为Test 主要用...
    99+
    2023-06-29
  • Go语言流程控制的示例分析
    这篇文章给大家分享的是有关Go语言流程控制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、流程控制流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑。流程控...
    99+
    2023-06-29
  • Go语言学习教程之反射的示例详解
    目录介绍反射的规律1. 从接口值到反射对象的反射2. 从反射对象到接口值的反射3. 要修改反射对象,该值一定是可设置的介绍 reflect包实现运行时反射,允许一个程序操作任何类型...
    99+
    2022-11-11
  • Go语言学习教程之指针的示例详解
    目录前言练习1练习2练习3前言 关于指针的主要几点: 指针类型:一个指针类型*T表示指向给定类型的变量的所有指针的集合,该给定类型T称为基本类型。未初始化的指针的值是nil。变量:一...
    99+
    2022-11-11
  • Go语言中go程释放操作的示例分析
    小编给大家分享一下Go语言中go程释放操作的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!go适合做什么go是golang的简称,而golang可以做服务...
    99+
    2023-06-14
  • Go语言中go doc命令用法及示例分析
    本篇文章给大家分享的是有关Go语言中go doc命令用法及示例分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。go doc为我们提供了快速生成文档以及查看文档的工具,让我们可...
    99+
    2023-06-25
  • Go语言中基础闭包的示例分析
    这篇文章将为大家详细讲解有关Go语言中基础闭包的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一. 闭包概述闭包就是解决局部变量不能被外部访问的一种解决方案闭包是把函数当作返回值的一种应用二. 代...
    99+
    2023-06-25
  • Go语言学习教程之结构体的示例详解
    目录前言可导出的标识符嵌入字段提升标签结构体与JSON相互转换结构体转JSONJSON转结构体练习代码步骤前言 结构体是一个序列,包含一些被命名的元素,这些被命名的元素称为字段(fi...
    99+
    2022-11-11
  • Go 语言结构实例分析
    当前的调试部分可以使用 go run filename.go 来执行。 可以生成一个 build.sh 脚本,用于在指定位置产生已编译好的 可执文件: #!/usr/bin/en...
    99+
    2022-11-12
  • Go语言学习教程之goroutine和通道的示例详解
    目录goroutine通道Range 和 CloseSelect官方留的两道练习题等价的二叉树网络爬虫源码地址goroutine goroutine是由Go运行时管理的轻量级线程。 ...
    99+
    2022-11-11
  • GO语言操作Elasticsearch示例分享
    目录Elasticsearch简介连接Elasticsearch创建索引创建model结构体初始化model创建索引搜索数据创建返回结构体搜索数据解析数据修改数据单条修改批量修改删除...
    99+
    2023-01-17
    golang操作Elasticsearch Go言操作ElasticSearch go操作elasticsearch示例
  • Go语言选择器实例分析
    今天小编给大家分享一下Go语言选择器实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。引言在 Go 语言中,表达式&nb...
    99+
    2023-07-02
  • C语言编程PAT乙级学习笔记示例分享
    目录1001 害死人不偿命的(3n+1)猜想1002 写出这个数1003 我要通过!1004 成绩排名1005 继续(3n+1)猜想1006 换个格式输出整数1007 素数对猜想问题...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作