Go语言otns源码分析

发布时间:2023-05-05 16:41:17 作者:iii
来源:亿速云 阅读:110

这篇“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);
}

这个方法接受一个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关键字包含了很多的消息体,每个消息体封装了一个事件。

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

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

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

visualize/grpc/replay目录下的文件

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

type grpcField struct {
   nodes       map[NodeId]*grpcNode
   curTime     uint64
   curSpeed    float64
   speed       float64
   titleInfo   visualize.TitleInfo
   networkInfo visualize.NetworkInfo
}

定义了节点结构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,包含信息如下

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

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

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

其中自定义了一个结构:

    type grpcVisualizer struct {
       simctrl             visualize.SimulationController
       server              *grpcServer
       f                   *grpcField
       showDemoLegendEvent *pb.VisualizeEvent
       replay              *replay.Replay
       sync.Mutex
    }
type SimulationController interface {
    Command(cmd string) ([]string, error)
}

大概就是命令的入口。

cmd/otns-replay目录下的文件

grpc_Service(包含pb)
type grpcService struct {
   replayFile string
}

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

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

启动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
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
}
simulation_config.go

定义了配置和默认配置

simulation.go
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
}

cli目录

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

ast.go

定义了各种命令结构

CmdRunner.go
type CmdRunner struct {
   sim           *simulation.Simulation
   ctx           *progctx.ProgCtx
   contextNodeId NodeId
}
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
}

以上就是关于“Go语言otns源码分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

推荐阅读:
  1. docker用go语言的原因是什么
  2. go语言是不是面向对象的

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

go语言 otns

上一篇:el-tree节点过滤不显示下级问题怎么解决

下一篇:kubernetes认证鉴权内容有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》