当前位置:首页 > 文章列表 > Golang > Go教程 > Go语言otns源码分析

Go语言otns源码分析

来源:亿速云 2023-05-06 06:50:02 0浏览 收藏

偷偷努力,悄无声息地变强,然后惊艳所有人!哈哈,小伙伴们又来学习啦~今天我将给大家介绍《Go语言otns源码分析》,这篇文章主要会讲到go语言等等知识点,不知道大家对其都有多少了解,下面我们就一起来看一吧!当然,非常希望大家能多多评论,给出合理的建议,我们一起学习,一起进步!

这篇“Go语言otns源码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Go语言otns源码分析”文章吧。

    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源码分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注golang学习网行业资讯频道。

    今天带大家了解了go语言的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

    版本声明
    本文转载于:亿速云 如有侵犯,请联系study_golang@163.com删除
    Go语言kube-scheduler之pod调度怎么实现Go语言kube-scheduler之pod调度怎么实现
    上一篇
    Go语言kube-scheduler之pod调度怎么实现
    规模扩大 10 倍,谷歌邀请更多 Gmail 和 Docs 用户测试生成式 AI
    下一篇
    规模扩大 10 倍,谷歌邀请更多 Gmail 和 Docs 用户测试生成式 AI
    查看更多
    最新文章
    查看更多
    课程推荐
    • 前端进阶之JavaScript设计模式
      前端进阶之JavaScript设计模式
      设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
      542次学习
    • GO语言核心编程课程
      GO语言核心编程课程
      本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
      508次学习
    • 简单聊聊mysql8与网络通信
      简单聊聊mysql8与网络通信
      如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
      497次学习
    • JavaScript正则表达式基础与实战
      JavaScript正则表达式基础与实战
      在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
      487次学习
    • 从零制作响应式网站—Grid布局
      从零制作响应式网站—Grid布局
      本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
      484次学习
    查看更多
    AI推荐
    • 笔灵AI生成答辩PPT:高效制作学术与职场PPT的利器
      笔灵AI生成答辩PPT
      探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
      24次使用
    • 知网AIGC检测服务系统:精准识别学术文本中的AI生成内容
      知网AIGC检测服务系统
      知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
      38次使用
    • AIGC检测服务:AIbiye助力确保论文原创性
      AIGC检测-Aibiye
      AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
      38次使用
    • 易笔AI论文平台:快速生成高质量学术论文的利器
      易笔AI论文
      易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
      50次使用
    • 笔启AI论文写作平台:多类型论文生成与多语言支持
      笔启AI论文写作平台
      笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
      41次使用
    查看更多
    相关文章
    微信登录更方便
    • 密码登录
    • 注册账号
    登录即同意 用户协议隐私政策
    返回登录
    • 重置密码