<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
由於在用虛擬機器器體驗過程中出現了未知的錯誤之後,打算使用wsl又遇到了安裝錯誤,各種辦法解決無果,於是我打算跳過體驗的這一部分,直接先進行這個例子中的grpc呼叫部分的梳理分析,等有空了再去解決一下wsl安裝不了的問題。
這個例子中只有一個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[]
定義了一個結構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()
方法,還自定義了其他的方法如run
、stop
、prepareStream
等等,看名字就容易知道是什麼用途
裡面自定義了一個結構grpcStream
,使用這個檔案中的newGrpcStream
可以將Visualize函數的伺服器端流賦到這個結構中
其中自定義了一個結構:
type grpcVisualizer struct { simctrl visualize.SimulationController server *grpcServer f *grpcField showDemoLegendEvent *pb.VisualizeEvent replay *replay.Replay sync.Mutex }
sync.Mutex
,並且包含了上面的grpcServer、grpcServer結構,這個檔案裡面的函數大概都是新增、刪除節點或者修改什麼資訊之類的,基本是呼叫了grpcField
和grpcServer
檔案裡面的函數,但是在呼叫之前加了鎖。visualize/types.go
中的Visualizer
介面visualize.SimulationController
介面的欄位,而visualize.SimulationController
定義如下:type SimulationController interface { Command(cmd string) ([]string, error) }
大概就是命令的入口。
grpcService
結構,並且實現了Visualize
和Command
兩個方法type grpcService struct { replayFile string }
2. grpcService
結構下的visualizeStream()
函數
將grpcService
的replay檔案檢驗並開啟,並且逐行讀取內容,並解析到var entry pb.ReplayEntry
中,再通過stream將entry.Event
傳送到服務的使用者端
Visualize
方法:啟動visualizeStream()
協程,建立一個心跳事件,每隔一秒心跳一下,直到上面的visualizeStream()
讀取完成
main()函數
一系列的校驗和設定引數之後,用上面的grpcService
結構註冊伺服器端,在本機地址8999
埠監聽。然後就是設定和開啟網頁
呼叫了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) }
建立一個新模擬,並設定CmdRunner
和Visualizer
:
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
是grpcVisualizer
和cmdRunner
通訊的橋樑。
定義了CmdRunner
介面:
type CmdRunner interface { RunCommand(cmd string, output io.Writer) error }
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
結構定義: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 }
simulation
結構的函數simulation
結構中的visualize.Visualizer
介面函數實現的cli目錄下定義了CmdRunner
及各種指令結構
定義了各種命令結構
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: %vn", err); err != nil { return err } } else { rt.execute(&cmd, output) } return nil }
RunCommand
方法中解析設定好命令後,有各種execute...()
函數來執行相應的命令,而在這些函數中又是通過呼叫simulation.Simulation
中對應的增刪改查函數來實現操作的以上就是Go語言學習otns範例分析的詳細內容,更多關於Go語言otns範例的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45