<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>网络 on cyp0633&#39;s Blog</title>
        <link>https://cyp0633.com/tags/networking/</link>
        <description>Recent content in 网络 on cyp0633&#39;s Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>cyp0633</copyright><atom:link href="https://cyp0633.com/tags/networking/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>ns-3 入门 5：追踪</title>
        <link>https://cyp0633.com/post/ns3-tracing/</link>
        <pubDate>Tue, 20 Feb 2024 10:52:00 +0800</pubDate>
        
        <guid>https://cyp0633.com/post/ns3-tracing/</guid>
        <description>&lt;p&gt;根据官方教程 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/tutorial/html/tracing.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Tracing&lt;/a&gt; 一章写成。原示例代码&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;和文中代码均以GPLv2发布。&lt;/p&gt;
&lt;p&gt;大家都知道仿真的目的是得到有价值的输出以进行分析，但对特定的分析目的来说，不同的输出方式可能分析效率不同。比如使用日志输出，其粒度仅为源代码文件和日志等级，对于更细的控制则略显不足，且日志输出的稳定性不作保证，可能随着更新而更改；而输出pcap可以记录每个数据包的细节，使用Wireshark筛选也更加直观简易，但不能体现仿真过程中的逻辑控制，如之前提到的Wi-Fi STA节点的移动轨迹。如果遇到并非自己代码中想要输出的内容，情况就更复杂了。比如开发者在教程中举了一个例子：为TCP socket添加一点输出，而这需要更改ns-3本身（在 &lt;code&gt;tcp-socket-base.cc&lt;/code&gt; 中）。虽然加输出确实很简单，但1) 更新ns-3版本时很麻烦，2) 仍需进行进一步日志筛选，3) 要重新编译ns-3。&lt;/p&gt;
&lt;p&gt;所以，使用ns-3的追踪工具是更好的选择，因为它可以只输出感兴趣的数据源，免去筛选的麻烦，并且直接从ns-3内部获取数据（而不用改ns-3的代码）。&lt;/p&gt;
&lt;p&gt;基本上，追踪接收器就是一个回调，是一个函数指针。将追踪源和接收器相连的操作，就是把接收器对应的回调传入对应追踪源的回调列表中。当追踪源执行的时候，它就依次执行每个接收器对应的回调。另外，被追踪的值采用值语义&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;传递，这使得它触发的时候是什么样，追踪出来就是什么样。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在不使用回调的情况下，若A要通过B的函数进行通信，A就必须依赖B。由于追踪接收器有很多，又不能逐个添加依赖，所以通过依赖的办法缺乏灵活性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;简单的示例代码&#34;&gt;简单的示例代码
&lt;/h2&gt;&lt;p&gt;开发者给出了 &lt;code&gt;fourth.cc&lt;/code&gt;&lt;sup id=&#34;fnref1:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; 作为入门代码示例。略过头文件部分，代码首先定义了一个 &lt;code&gt;Object&lt;/code&gt; 的子类，添加了一个追踪源数据，并实现了 &lt;code&gt;GetTypeId&lt;/code&gt; 方法：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-0&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-0&#34; style=&#34;display:none;&#34;&gt;class MyObject : public Object
{
  public:
    /**
     * Register this type.
     * \return The TypeId.
     */
    static TypeId GetTypeId()
    {
        static TypeId tid = TypeId(&amp;#34;MyObject&amp;#34;)
                                .SetParent&amp;lt;Object&amp;gt;()
                                .SetGroupName(&amp;#34;Tutorial&amp;#34;)
                                .AddConstructor&amp;lt;MyObject&amp;gt;()
                                .AddTraceSource(&amp;#34;MyInteger&amp;#34;,
                                                &amp;#34;An integer value to trace.&amp;#34;,
                                                MakeTraceSourceAccessor(&amp;amp;MyObject::m_myInt),
                                                &amp;#34;ns3::TracedValueCallback::Int32&amp;#34;);
        return tid;
    }
    MyObject()
    {
    }
    TracedValue&amp;lt;int32_t&amp;gt; m_myInt; //!&amp;lt; The traced value.
};&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;21
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;22
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;23
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;MyObject&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Register this type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * \return The TypeId.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeId&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GetTypeId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeId&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;MyObject&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetParent&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetGroupName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Tutorial&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AddConstructor&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MyObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AddTraceSource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;MyInteger&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                &lt;span class=&#34;s&#34;&gt;&amp;#34;An integer value to trace.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                &lt;span class=&#34;n&#34;&gt;MakeTraceSourceAccessor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MyObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_myInt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                &lt;span class=&#34;s&#34;&gt;&amp;#34;ns3::TracedValueCallback::Int32&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;TracedValue&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int32_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;m_myInt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//!&amp;lt; The traced value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果真的按照官方教程去走，一定会晕头转向，因为官方教程的路线根本没提到ns-3的对象模型。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ns-3提供了三个基类，&lt;code&gt;Object&lt;/code&gt;、&lt;code&gt;ObjectBase&lt;/code&gt; 和 &lt;code&gt;SimpleRefCount&lt;/code&gt;。&lt;code&gt;SimpleRefCount&lt;/code&gt; 具有ns-3智能指针（&lt;code&gt;Ptr&lt;/code&gt;）的引用计数，&lt;code&gt;ObjectBase&lt;/code&gt; 具有类型（即 &lt;code&gt;GetTypeId&lt;/code&gt; 这一堆）和属性信息以及对象聚合（目前没用到）。&lt;code&gt;Object&lt;/code&gt; 具有以上两者的所有特性，如 &lt;code&gt;NetDevice&lt;/code&gt; 和 &lt;code&gt;TcpSocketState&lt;/code&gt; 全部是它的子类。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;TypeId&lt;/code&gt; 是 &lt;code&gt;Object&lt;/code&gt; 的子类可选包含的一个属性，用于存放该类的元数据，如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标识这个类的唯一字符串（&lt;code&gt;MyObject&lt;/code&gt;），用于进行运行时类型推导&lt;/li&gt;
&lt;li&gt;父类（&lt;code&gt;Object&lt;/code&gt;），用于进行向上/向下类型转换&lt;/li&gt;
&lt;li&gt;可用的构造函数，用于在不知道对象具体类型的情况下创建对象&lt;/li&gt;
&lt;li&gt;可公开访问属性（attribute）列表，需要同时提供访问方法和边界检查&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;除了以上四条之外，可以看到 &lt;code&gt;AddTraceSource&lt;/code&gt; 方法，用于添加一个追踪源。它的用法有点像 &lt;code&gt;AddAttribute&lt;/code&gt;，不同的是1) 由于是内部编辑，所以不需要像attribute一样做边界检查；2) 有一个回调函数，用于在触发时执行。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;m_myint&lt;/code&gt; 就是被追踪的数据，而 &lt;code&gt;TracedValue&lt;/code&gt; 类型用于除了包装 &lt;code&gt;int32_t&lt;/code&gt; 之外，还具备在值变化时触发回调的功能，并要求回调函数&lt;strong&gt;有且仅有&lt;/strong&gt;两个 &lt;code&gt;int32_t&lt;/code&gt; 参数，分别是旧值和新值。至于 &lt;code&gt;MakeTraceSourceAccessor&lt;/code&gt;，则用于连接追踪源和追踪接收器，反正加上就行了。&lt;/p&gt;
&lt;p&gt;对应的，&lt;code&gt;IntTrace&lt;/code&gt; 函数中就是 &lt;code&gt;MyInteger&lt;/code&gt; 追踪源对应的接收回调，没有返回值，有且仅有两个 &lt;code&gt;int32_t&lt;/code&gt; 参数，代码简单易懂：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-1&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-1&#34; style=&#34;display:none;&#34;&gt;void
IntTrace(int32_t oldValue, int32_t newValue)
{
    std::cout &amp;lt;&amp;lt; &amp;#34;Traced &amp;#34; &amp;lt;&amp;lt; oldValue &amp;lt;&amp;lt; &amp;#34; to &amp;#34; &amp;lt;&amp;lt; newValue &amp;lt;&amp;lt; std::endl;
}&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;IntTrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oldValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cout&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Traced &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oldValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34; to &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;endl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;最后在 &lt;code&gt;main&lt;/code&gt; 函数中，就是创建对象和连接的过程了。&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-2&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-2&#34; style=&#34;display:none;&#34;&gt;int
main(int argc, char* argv[])
{
    Ptr&amp;lt;MyObject&amp;gt; myObject = CreateObject&amp;lt;MyObject&amp;gt;();
    myObject-&amp;gt;TraceConnectWithoutContext(&amp;#34;MyInteger&amp;#34;, MakeCallback(&amp;amp;IntTrace));

    myObject-&amp;gt;m_myInt = 1234;

    return 0;
}&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Ptr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MyObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;myObject&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CreateObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MyObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;myObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TraceConnectWithoutContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;MyInteger&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MakeCallback&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;IntTrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;myObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_myInt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1234&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;对于 &lt;code&gt;Object&lt;/code&gt; 的子类，应该使用 &lt;code&gt;CreateObject()&lt;/code&gt; 函数创建对象实例，对应的也会返回一个 &lt;code&gt;Ptr&lt;/code&gt;。而对于 &lt;code&gt;SimpleRefCount&lt;/code&gt; 的子类，则使用 &lt;code&gt;Create()&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;此处连接使用的并不是示例代码3（third.cc）中使用的 &lt;code&gt;Config::Connect()&lt;/code&gt; 搭配绝对路径识别符，而是直接使用 &lt;code&gt;MyObject&lt;/code&gt; 的 &lt;code&gt;TraceConnectWithoutContext()&lt;/code&gt; 成员函数，这样在第一个参数中就只需要写该类下追踪源的名字而非完整路径了。&lt;code&gt;MakeCallback&lt;/code&gt; 的作用这里不再赘述。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;此处与示例代码3中另一个显著的不同是后者使用带context的追踪，&lt;code&gt;TraceConnect()&lt;/code&gt; 成员函数中第二个参数为 &lt;code&gt;std::string&lt;/code&gt; 类型，用来描述上下文（如对象路径），其会作为第一个参数传入回调，而此处使用的 &lt;code&gt;TraceConnectWithoutContext()&lt;/code&gt; 就没有。也就是说，如果使用带context的追踪，那么回调函数应该改为 &lt;code&gt;void IntTrace(std::string context, int32_t oldValue, int32_t newValue)&lt;/code&gt;。&lt;code&gt;Config::Connect()&lt;/code&gt; 和 &lt;code&gt;Config::ConnectWithoutContext()&lt;/code&gt; 则都不需要额外传入上下文信息。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;使用-config-子系统&#34;&gt;使用 &lt;code&gt;Config&lt;/code&gt; 子系统
&lt;/h2&gt;&lt;p&gt;虽然这种 &lt;code&gt;TraceConnect()&lt;/code&gt; 很实用，但据开发者声称，一般来说都会使用所谓的配置路径选择追踪源，就像之前在示例代码3中一样。也就是说，以下两个部分的代码是等效的：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-3&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-3&#34; style=&#34;display:none;&#34;&gt;// 使用 Config::Connect
std::ostringstream oss;
oss &amp;lt;&amp;lt; &amp;#34;/NodeList/&amp;#34; &amp;lt;&amp;lt; wifiStaNodes.Get(nWifi - 1)-&amp;gt;GetId()
    &amp;lt;&amp;lt; &amp;#34;/$ns3::MobilityModel/CourseChange&amp;#34;;
Config::Connect(oss.str(), MakeCallback(&amp;amp;CourseChange););

// 使用 TraceConnect
wifiStaNodes.Get(nWifi - 1)-&amp;gt;GetObject&amp;lt;MobilityModel&amp;gt;()
    -&amp;gt;TraceConnect(&amp;#34;CourseChange&amp;#34;, MakeCallback(&amp;amp;CourseChange));&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 使用 Config::Connect
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ostringstream&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oss&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;oss&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/NodeList/&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wifiStaNodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nWifi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/$ns3::MobilityModel/CourseChange&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;oss&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MakeCallback&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CourseChange&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;););&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 使用 TraceConnect
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wifiStaNodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nWifi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MobilityModel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TraceConnect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;CourseChange&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MakeCallback&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CourseChange&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/nsnam/ns-3-dev/-/blob/2d04193b54bc57c29a229b0930f38dba903906ce/examples/tutorial/fourth.cc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://gitlab.com/nsnam/ns-3-dev/-/blob/2d04193b54bc57c29a229b0930f38dba903906ce/examples/tutorial/fourth.cc&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/questions/166033/what-do-value-semantics-and-pointer-semantics-mean&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://stackoverflow.com/questions/166033/what-do-value-semantics-and-pointer-semantics-mean&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
        </item>
        <item>
        <title>ns-3 入门 4：构建拓扑</title>
        <link>https://cyp0633.com/post/ns3-topology/</link>
        <pubDate>Wed, 14 Feb 2024 16:29:00 +0800</pubDate>
        
        <guid>https://cyp0633.com/post/ns3-topology/</guid>
        <description>&lt;p&gt;根据官方教程 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/tutorial/html/building-topologies.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Building Topologies&lt;/a&gt; 一章写成。原示例代码&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;和文中代码均以GPLv2发布。&lt;/p&gt;
&lt;h2 id=&#34;总线拓扑&#34;&gt;总线拓扑
&lt;/h2&gt;&lt;p&gt;第二篇示例代码&lt;sup id=&#34;fnref1:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;描述了一个简单的例子，默认共有5个节点，$n_0$ 和 $n_1$ 通过点对点链路相连，网段为10.1.1.0/24；$n_1$ 到 $n_{i+1}$ 共 ${i+1}$ 个节点（$i$ 为 &lt;code&gt;nCsma&lt;/code&gt; 参数的值，默认为3）通过共享介质的CSMA网络连接（有点类似Ethernet），使用10.1.2.0/24网段。其中 $n_1$ 同时连接了两个网络。之后在 $n_0$ 上设置示例代码1一样的echo client，在 $n_{i+1}$ 上设置对应的echo server。&lt;/p&gt;
&lt;p&gt;代码大多跟之前的第一个示例没什么不同，只是有了更多的节点和设备。然而还是有一些需要注意的地方：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个节点可以同时属于多个 &lt;code&gt;NodeContainer&lt;/code&gt;，如 $n_1$，这样就方便在同一个节点上设置多个设备了。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NodeContainer.Create&lt;/code&gt; 函数会在当前container的基础上增加指定数量的节点，而非用指定数量初始化。&lt;/li&gt;
&lt;li&gt;由于不在同一个网段内，两个网段自然是不互通的，于是需要使用 &lt;code&gt;Ipv4StaticRoutingHelper::PopulateRoutingTables()&lt;/code&gt; 让所有节点都能充当路由器的功能，并填充路由表。类似于Linux的 &lt;code&gt;sysctl -w net.ipv4.ip_forward=1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;对于 &lt;code&gt;CsmaChannel&lt;/code&gt; 之类可以同时连接多个设备的信道，可以在某一节点上启用混杂（&lt;em&gt;promiscuous&lt;/em&gt;）模式（如代码113行），这样就可以监听到所有经过该信道的数据包了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;程序一共录制了三个pcap文件。可以看到，在 &lt;code&gt;second-0-0.pcap&lt;/code&gt; 和 &lt;code&gt;second-1-0.pcap&lt;/code&gt; 中，只有基于点对点协议的UDP包，但在 &lt;code&gt;second-2-0.pcap&lt;/code&gt; 中，不光变成了网段不同、基于Ethernet的UDP包，还出现了ARP包，以进行IP到MAC地址的查找。&lt;/p&gt;
&lt;p&gt;为了更高的可自定义度，&lt;code&gt;EnablePcap&lt;/code&gt; 不仅可以接受网络设备指针（&lt;code&gt;nd: Ptr&amp;lt;NetDevice&amp;gt;&lt;/code&gt;），也可以接受节点 &lt;strong&gt;ID&lt;/strong&gt;（&lt;code&gt;nodeid: uint32_t&lt;/code&gt;）&lt;strong&gt;和设备ID&lt;/strong&gt;（&lt;code&gt;deviceid: uint32_t&lt;/code&gt;）。换而言之，以下两行代码是等效的：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-0&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-0&#34; style=&#34;display:none;&#34;&gt;csma.EnablePcap(&amp;#34;second&amp;#34;,csmaDevices.Get(1),true);
csma.EnablePcap(&amp;#34;second&amp;#34;,csmaNodes.Get(1)-&amp;gt;GetId(),0,true);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;csma&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EnablePcap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;second&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;csmaDevices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;csma&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EnablePcap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;second&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;csmaNodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Get&lt;/code&gt; 中输入的参数为节点在该容器中的索引，而非节点ID。节点ID是全局共享、递增的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;模型属性和现实&#34;&gt;模型、属性和现实
&lt;/h2&gt;&lt;p&gt;在官方教程的对应章节中，主要是想提醒使用者须清楚认识到建模并不一定能涵盖真实情况的所有方面。比如上一节中 &lt;code&gt;CsmaChannel&lt;/code&gt; 相对于真实Ethernet&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; 来说并没有碰撞检测特性，而这是很容易被使用者忽略的。&lt;/p&gt;
&lt;p&gt;另外作者还提到了不同网络标准中的不同属性。比如Ethernet的常见最大包大小为1518字节，而由于Ethernet II（DIX）标准的封装方式比IEEE 802.2（LLC/SNAP） 的协议开销少8个字节&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;，所以前者允许的最大MTU可以高一点。在ns-3的 &lt;code&gt;CsmaNetDevice&lt;/code&gt; 中，MTU和封装方式是两个单独的属性，若采用了后者的封装方式而忘了更改默认为1500的MTU，虽然模拟能够正常运行，但&lt;strong&gt;可能&lt;/strong&gt;会偏离实际情况。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里不是说MTU=1500同时采用LLC/SNAP一定是错的，现代部分网络甚至允许MTU=9000的Jumbo Frame，最终一切还是要看具体情况。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;构建无线拓扑&#34;&gt;构建无线拓扑
&lt;/h2&gt;&lt;p&gt;这一段的示例代码&lt;sup id=&#34;fnref1:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;在第二篇代码中增加了一个无线网络，并连接到 $n_0$，Wi-Fi使用802.11a标准（有点远古），网段为10.1.3.0/24。随附示例代码中描述拓扑的字符画：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-1&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-1&#34; style=&#34;display:none;&#34;&gt;// Default Network Topology
//
//   Wifi 10.1.3.0
//                 AP
//  *    *    *    *
//  |    |    |    |    10.1.1.0
// n5   n6   n7   n0 -------------- n1   n2   n3   n4
//                   point-to-point  |    |    |    |
//                                   ================
//                                     LAN 10.1.2.0&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Default Network Topology
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//   Wifi 10.1.3.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//                 AP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  *    *    *    *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  |    |    |    |    10.1.1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// n5   n6   n7   n0 -------------- n1   n2   n3   n4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//                   point-to-point  |    |    |    |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//                                   ================
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//                                     LAN 10.1.2.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在上面总线拓扑的基础上，又添加了 &lt;code&gt;YansWifiChannel&lt;/code&gt;，相对来说更复杂一点，但从始至终都是围着链路层和物理层工作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$n_0$ 作为AP，其他节点作为STA，分到两个 &lt;code&gt;NodeContainer&lt;/code&gt; 中。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;YansWifiPhyHelper&lt;/code&gt; 来设置物理层属性，如频率、速率等。它承担了类似 &lt;code&gt;CsmaHelper&lt;/code&gt; 的功能，只不过不能直接包办建立起信道和安装网络设备了。&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;WifiMacHelper&lt;/code&gt; 区分AP和STA，并设置同一个SSID来确保连接同一个网络。&lt;/li&gt;
&lt;li&gt;AP和STA的网络设备也有所不同，所以也包含在两个 &lt;code&gt;NetDeviceContainer&lt;/code&gt; 中，但可以使用同一个 &lt;code&gt;WifiHelper&lt;/code&gt;（用于安装网络设备）。&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;MobilityHelper&lt;/code&gt; 模拟STA节点走来走去，而AP节点则固定在原地。&lt;/li&gt;
&lt;li&gt;用同一个 &lt;code&gt;Ipv4AddressHelper&lt;/code&gt; 在同一次 &lt;code&gt;Setbase&lt;/code&gt; 之后多次 &lt;code&gt;Assign&lt;/code&gt; 来保证AP和STA在同一个网段内（相当于使用固定IP，不考虑复杂的DHCP）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在STA节点的链路层设置中（&lt;code&gt;WifiMacHelper&lt;/code&gt;），可以看到设置了 &lt;code&gt;ActiveProbing&lt;/code&gt; 属性，这使得STA节点会一直搜寻AP，导致仿真永远不会结束。因此，还需要在开始前手动设置10s结束仿真。&lt;/p&gt;
&lt;p&gt;并不需要对Wi-Fi网络启用混杂模式，因为Wi-Fi网络的数据包都是广播的，所以所有节点都能收到。换而言之，混杂模式是自动开启的。&lt;/p&gt;
&lt;p&gt;如果加上 &lt;code&gt;--trace&lt;/code&gt; 参数，会记录下来4个文件，其中 &lt;code&gt;third-0-1.pcap&lt;/code&gt; 对应的是Wi-Fi的流量。使用工具读取，可以看到相比Ethernet，Wi-Fi的通信更加复杂，还有beacon frame之类的控制信息。&lt;/p&gt;
&lt;h3 id=&#34;记录sta移动轨迹&#34;&gt;记录STA移动轨迹
&lt;/h3&gt;&lt;p&gt;之前在介绍跟踪时，并未明确跟踪接收器的设计办法，使用的也是helper自带的连接方式。而在这个示例代码中，为了追踪某个STA的移动轨迹并打印到日志中，需要自行设计跟踪接收器（其实就是一个函数），并设置回调。这里的跟踪接收器也只是个函数而已：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-2&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-2&#34; style=&#34;display:none;&#34;&gt;void
CourseChange(std::string context, Ptr&amp;lt;const MobilityModel&amp;gt; model)
{
  Vector position = model-&amp;gt;GetPosition();
  NS_LOG_UNCOND(context &amp;lt;&amp;lt;
              &amp;#34; x = &amp;#34; &amp;lt;&amp;lt; position.x &amp;lt;&amp;lt; &amp;#34;, y = &amp;#34; &amp;lt;&amp;lt; position.y);
}&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;CourseChange&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Ptr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MobilityModel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;Vector&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;position&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetPosition&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;NS_LOG_UNCOND&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;s&#34;&gt;&amp;#34; x = &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;position&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;, y = &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;position&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其实功能非常简单，就是当调用这个函数的时候，打印出对应的事件名（context），以及STA节点的位置。为了让节点位置变化时调用这个函数，需要在 &lt;code&gt;Simulator::Run()&lt;/code&gt; 之前设置回调：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-3&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-3&#34; style=&#34;display:none;&#34;&gt;std::ostringstream oss;
oss &amp;lt;&amp;lt; &amp;#34;/NodeList/&amp;#34; &amp;lt;&amp;lt; wifiStaNodes.Get(nWifi - 1)-&amp;gt;GetId()
    &amp;lt;&amp;lt; &amp;#34;/$ns3::MobilityModel/CourseChange&amp;#34;;
auto cb = MakeCallback(&amp;amp;CourseChange);
Config::Connect(oss.str(), cb);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ostringstream&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oss&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;oss&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/NodeList/&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wifiStaNodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nWifi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/$ns3::MobilityModel/CourseChange&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MakeCallback&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CourseChange&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;oss&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Config::Connect()&lt;/code&gt; 的第一个参数就是事件名，也就是跟踪源的路径，这里仅指定了一个STA。第二个参数就是一个回调对象。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;MakeCallback&lt;/code&gt; 的作用是将函数指针包装成一个 &lt;code&gt;Callback&lt;/code&gt; 对象。&lt;code&gt;Callback&lt;/code&gt; 类是一个模板类，有一个强制参数（对应返回值，void也算一个）和至多五个可选参数（对应参数列表）。&lt;code&gt;MakeCallback&lt;/code&gt; 会根据函数指针的类型自动推断参数列表。这样，就可以直接使用类似 &lt;code&gt;ret = cb(arg1, arg2, ...)&lt;/code&gt; 的方法来调用回调了。如果需要设置对象的成员函数回调，或者希望预先设定某几个参数，可以参考 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/manual/html/callbacks.html#using-the-callback-api-with-member-functions&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;手册的对应部分&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这样，当STA位置变化时，就会在日志中打印当前位置，如：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;plaintext&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-4&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-4&#34; style=&#34;display:none;&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.36083, y = -0.769065
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.62346, y = 0.195831
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.42533, y = 1.17601
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.4854, y = 0.834616
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.79244, y = 1.55559
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.85546, y = 2.55361&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.36083, y = -0.769065
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.62346, y = 0.195831
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.42533, y = 1.17601
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.4854, y = 0.834616
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.79244, y = 1.55559
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.85546, y = 2.55361&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&#34;ns-3中的队列&#34;&gt;ns-3中的队列
&lt;/h2&gt;&lt;p&gt;和很多人理解的不同，数据包并不是排一个队就能直接发出去了，而在实际情况中，有多层队列，排完这个再排下一个，用来处理不同的事情。在ns-3中虽然并没有实际操作系统中那么复杂，但也“将IP层或流量控制层与设备层分开”，前者，即所谓的流量控制层，处理QoS和AQM；而后者在 &lt;code&gt;NetDevice&lt;/code&gt; 中，处理设备层的队列，与连接类型有关（Ethernet，Wi-Fi等）。如果设备层的队列并没有被填满，那么流量控制层队列基本等效于透明，毕竟这时并没有控制流量的必要。&lt;/p&gt;
&lt;p&gt;官方教程中有 [不同队列类型详解]。在分配IP地址时，流量控制层默认启用 &lt;code&gt;pfifo_fast&lt;/code&gt; 队列（容量为1000个包）并可以自行指定，而设备层队列由设备自身决定，不同的网络设备有不同的队列类型。&lt;/p&gt;
&lt;p&gt;若要自行指定流量控制层的队列，有两种办法。如果还未安装网络设备，可以借助网络设备的helper实现：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-5&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-5&#34; style=&#34;display:none;&#34;&gt;PointToPointHelper p2p;
p2p.SetQueue(&amp;#34;ns3::DropTailQueue&amp;#34;, &amp;#34;MaxSize&amp;#34;, StringValue(&amp;#34;50p&amp;#34;));
NetDeviceContainer devices = p2p.Install(nodes);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;PointToPointHelper&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p2p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;p2p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ns3::DropTailQueue&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;MaxSize&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;50p&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;NetDeviceContainer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;devices&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p2p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果已经安装了网络设备，可以使用 &lt;code&gt;TrafficControlHelper&lt;/code&gt; 来设置根队列：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-6&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-6&#34; style=&#34;display:none;&#34;&gt;TrafficControlHelper tch;
tch.SetRootQueueDisc(&amp;#34;ns3::CoDelQueueDisc&amp;#34;, &amp;#34;MaxSize&amp;#34;, StringValue(&amp;#34;1000p&amp;#34;));
tch.Install(devices);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;TrafficControlHelper&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;tch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetRootQueueDisc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ns3::CoDelQueueDisc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;MaxSize&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;1000p&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;tch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/nsnam/ns-3-dev/-/blob/2209a5abd18be77c6c865c837368b4e459ae7c8e/examples/tutorial/second.cc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://gitlab.com/nsnam/ns-3-dev/-/blob/2209a5abd18be77c6c865c837368b4e459ae7c8e/examples/tutorial/second.cc&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/nsnam/ns-3-dev/-/blob/5649b4801cc3e06b8d0edc9ea1b18510594dfd35/examples/tutorial/third.cc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://gitlab.com/nsnam/ns-3-dev/-/blob/5649b4801cc3e06b8d0edc9ea1b18510594dfd35/examples/tutorial/third.cc&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;早期的共享介质Ethernet标准使用CSMA/CD，而非CSMA。&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Ethernet_frame#Types&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://en.wikipedia.org/wiki/Ethernet_frame#Types&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
        </item>
        <item>
        <title>ns-3 入门 3：日志、命令参数和跟踪</title>
        <link>https://cyp0633.com/post/ns3-tweaks/</link>
        <pubDate>Sat, 03 Feb 2024 12:18:00 +0800</pubDate>
        
        <guid>https://cyp0633.com/post/ns3-tweaks/</guid>
        <description>&lt;p&gt;根据官方教程 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/tutorial/html/tweaking.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Tweaking&lt;/a&gt; 一章写成。&lt;/p&gt;
&lt;h2 id=&#34;日志&#34;&gt;日志
&lt;/h2&gt;&lt;p&gt;ns-3自带一个日志系统。用日志系统记录输出和错误等是常见的做法，但由于追踪系统的存在（可以使用tcpdump或者Wireshark看），日志系统还是用来记录错误和调试信息为主。&lt;/p&gt;
&lt;p&gt;前面讲到ns-3的日志系统粒度为模块，可以对某个模块启用、禁用、设置级别等。&lt;/p&gt;
&lt;h3 id=&#34;日志级别&#34;&gt;日志级别
&lt;/h3&gt;&lt;p&gt;日志系统有以下几个级别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LOG_ERROR&lt;/code&gt;：错误&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOG_WARN&lt;/code&gt;：警告&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOG_DEBUG&lt;/code&gt;：临时的调试信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOG_INFO&lt;/code&gt;：程序运行进度等信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOG_FUNCTION&lt;/code&gt;：函数调用信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOG_LOGIC&lt;/code&gt;：函数内部的逻辑执行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOG_ALL&lt;/code&gt;：包含以上所有&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;LOG_FUNCTION&lt;/code&gt; 等级会在每个函数执行时打印信息，比如下面这样。&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;log&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-0&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-0&#34; style=&#34;display:none;&#34;&gt;UdpEchoClientApplication:UdpEchoClient(0xef90d0)
UdpEchoClientApplication:SetDataSize(0xef90d0, 1024)
UdpEchoClientApplication:StartApplication(0xef90d0)
UdpEchoClientApplication:ScheduleTransmit(0xef90d0, &amp;#43;0ns)
UdpEchoClientApplication:Send(0xef90d0)&lt;/code&gt;&lt;pre&gt;&lt;code class=&#34;&#34;&gt;UdpEchoClientApplication:UdpEchoClient(0xef90d0)
UdpEchoClientApplication:SetDataSize(0xef90d0, 1024)
UdpEchoClientApplication:StartApplication(0xef90d0)
UdpEchoClientApplication:ScheduleTransmit(0xef90d0, &amp;#43;0ns)
UdpEchoClientApplication:Send(0xef90d0)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;需要注意以上每种日志级别仅包含其本身。若要包含上级日志，则可使用对应的 &lt;code&gt;LOG_LEVEL&lt;/code&gt;。如 &lt;code&gt;LOG_LEVEL_DEBUG&lt;/code&gt; 是 &lt;code&gt;LOG_ERROR&lt;/code&gt;、&lt;code&gt;LOG_WARN&lt;/code&gt;、&lt;code&gt;LOG_DEBUG&lt;/code&gt; 三者的并集，皆会打印。&lt;/p&gt;
&lt;p&gt;另外还有一种 &lt;code&gt;LOG_UNCOND&lt;/code&gt; 级别，会打印任何日志条目，无视等级。&lt;/p&gt;
&lt;h3 id=&#34;设置级别&#34;&gt;设置级别
&lt;/h3&gt;&lt;p&gt;有两种办法对模块日志级别进行设置：环境变量和代码。环境变量设置不需要重新编译，所以比较方便。官方教程提到可以用环境变量“提高日志记录级别”，实际测试发现最终输出的日志范围是对两者取&lt;strong&gt;并集&lt;/strong&gt;（包括下文的日志前缀部分）。&lt;/p&gt;
&lt;p&gt;如果使用代码，需要使用 &lt;code&gt;LogComponentEnable&lt;/code&gt; 函数，若要设置多个模块的日志级别，多次调用该函数即可。比如将 &lt;code&gt;UdpEchoClientApplication&lt;/code&gt; 的日志级别设为 &lt;code&gt;INFO&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-1&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-1&#34; style=&#34;display:none;&#34;&gt;LogComponentEnable(&amp;#34;UdpEchoClientApplication&amp;#34;, LOG_LEVEL_INFO);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;LogComponentEnable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;UdpEchoClientApplication&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOG_LEVEL_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果只想要启用某个模块的自定义等级日志，可以使用并运算：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-2&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-2&#34; style=&#34;display:none;&#34;&gt;LogComponentEnable(&amp;#34;UdpEchoClientApplication&amp;#34;, LogLevel(LOG_INFO | LOG_FUNCTION));&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;LogComponentEnable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;UdpEchoClientApplication&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LogLevel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LOG_INFO&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOG_FUNCTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;而控制日志级别的环境变量是 &lt;code&gt;NS_LOG&lt;/code&gt;，虽然只有一个变量，但使用和PATH类似的表示方法，也可以控制多个模块的级别，其值的格式为 &lt;code&gt;Component1=level_1:Component2=level_2&lt;/code&gt;。比如：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-3&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-3&#34; style=&#34;display:none;&#34;&gt;export NS_LOG=&amp;#34;UdpEchoClientApplication=level_all:UdpEchoServerApplication=level_all&amp;#34;&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;NS_LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;UdpEchoClientApplication=level_all:UdpEchoServerApplication=level_all&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;环境变量表示的并运算会更加直观些：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-4&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-4&#34; style=&#34;display:none;&#34;&gt;export NS_LOG=&amp;#34;UdpEchoClientApplication=level_info|level_function&amp;#34;&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;NS_LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;UdpEchoClientApplication=level_info|level_function&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果需要设置所有模块的日志级别，可以将 &lt;code&gt;*&lt;/code&gt; 作为 &lt;code&gt;Component&lt;/code&gt; 的值。需注意该选项会导致大量输出。&lt;/p&gt;
&lt;h3 id=&#34;日志前缀&#34;&gt;日志前缀
&lt;/h3&gt;&lt;p&gt;回想第一个示例代码的输出，前面的日志输出的几乎都只有内容。比如之前那个示例程序，在启用所有日志等级时，输出是这样的：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;log&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-5&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-5&#34; style=&#34;display:none;&#34;&gt;UdpEchoServerApplication:UdpEchoServer(0x55fd771b1b10)
UdpEchoClientApplication:UdpEchoClient(0x55fd771d9570)
UdpEchoClientApplication:SetDataSize(0x55fd771d9570, 1024)
UdpEchoServerApplication:StartApplication(0x55fd771b1b10)
UdpEchoClientApplication:StartApplication(0x55fd771d9570)
UdpEchoClientApplication:ScheduleTransmit(0x55fd771d9570, &amp;#43;0ns)
UdpEchoClientApplication:Send(0x55fd771d9570)
At time &amp;#43;2s client sent 1024 bytes to 10.1.1.2 port 9
UdpEchoServerApplication:HandleRead(0x55fd771b1b10, 0x55fd771e5e70)
At time &amp;#43;2.00369s server received 1024 bytes from 10.1.1.1 port 49153
Echoing packet
......&lt;/code&gt;&lt;pre&gt;&lt;code class=&#34;&#34;&gt;UdpEchoServerApplication:UdpEchoServer(0x55fd771b1b10)
UdpEchoClientApplication:UdpEchoClient(0x55fd771d9570)
UdpEchoClientApplication:SetDataSize(0x55fd771d9570, 1024)
UdpEchoServerApplication:StartApplication(0x55fd771b1b10)
UdpEchoClientApplication:StartApplication(0x55fd771d9570)
UdpEchoClientApplication:ScheduleTransmit(0x55fd771d9570, &amp;#43;0ns)
UdpEchoClientApplication:Send(0x55fd771d9570)
At time &amp;#43;2s client sent 1024 bytes to 10.1.1.2 port 9
UdpEchoServerApplication:HandleRead(0x55fd771b1b10, 0x55fd771e5e70)
At time &amp;#43;2.00369s server received 1024 bytes from 10.1.1.1 port 49153
Echoing packet
......&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;日志前缀内容可以和日志输出等级一起设定，目前有如下几个选项&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PREFIX_FUNC&lt;/code&gt;： 函数名（格式为 &lt;code&gt;ComponentName:FunctionName&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PREFIX_TIME&lt;/code&gt;：仿真已进行的时长&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PREFIX_NODE&lt;/code&gt;：节点编号（就是之前关键抽象中的那个节点）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PREFIX_LEVEL&lt;/code&gt;：日志等级&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也可以用 &lt;code&gt;PREFIX_ALL&lt;/code&gt; 一次性打开所有前缀。以使用代码的方式为例，可以这样设置：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-6&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-6&#34; style=&#34;display:none;&#34;&gt;    LogComponentEnable(&amp;#34;UdpEchoClientApplication&amp;#34;,
                       LogLevel(ns3::LOG_LEVEL_ALL | ns3::LOG_PREFIX_ALL));
    LogComponentEnable(&amp;#34;UdpEchoServerApplication&amp;#34;,
                       LogLevel(ns3::LOG_LEVEL_ALL | ns3::LOG_PREFIX_ALL));&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;LogComponentEnable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;UdpEchoClientApplication&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       &lt;span class=&#34;n&#34;&gt;LogLevel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LOG_LEVEL_ALL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ns3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LOG_PREFIX_ALL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;LogComponentEnable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;UdpEchoServerApplication&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       &lt;span class=&#34;n&#34;&gt;LogLevel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ns3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LOG_LEVEL_ALL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ns3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LOG_PREFIX_ALL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;输出便成了这样：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;log&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-7&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-7&#34; style=&#34;display:none;&#34;&gt;&amp;#43;0.000000000s -1 UdpEchoServerApplication:UdpEchoServer(0x55b8911fcb10)
&amp;#43;0.000000000s -1 UdpEchoClientApplication:UdpEchoClient(0x55b891224570)
&amp;#43;0.000000000s -1 UdpEchoClientApplication:SetDataSize(0x55b891224570, 1024)
&amp;#43;1.000000000s 1 UdpEchoServerApplication:StartApplication(0x55b8911fcb10)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:StartApplication(0x55b891224570)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:ScheduleTransmit(0x55b891224570, &amp;#43;0ns)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:Send(0x55b891224570)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:Send(): [INFO ] At time &amp;#43;2s client sent 1024 bytes to 10.1.1.2 port 9
&amp;#43;2.003686400s 1 UdpEchoServerApplication:HandleRead(0x55b8911fcb10, 0x55b891230e70)
&amp;#43;2.003686400s 1 UdpEchoServerApplication:HandleRead(): [INFO ] At time &amp;#43;2.00369s server received 1024 bytes from 10.1.1.1 port 49153
&amp;#43;2.003686400s 1 UdpEchoServerApplication:HandleRead(): [LOGIC] Echoing packet
......&lt;/code&gt;&lt;pre&gt;&lt;code class=&#34;&#34;&gt;&amp;#43;0.000000000s -1 UdpEchoServerApplication:UdpEchoServer(0x55b8911fcb10)
&amp;#43;0.000000000s -1 UdpEchoClientApplication:UdpEchoClient(0x55b891224570)
&amp;#43;0.000000000s -1 UdpEchoClientApplication:SetDataSize(0x55b891224570, 1024)
&amp;#43;1.000000000s 1 UdpEchoServerApplication:StartApplication(0x55b8911fcb10)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:StartApplication(0x55b891224570)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:ScheduleTransmit(0x55b891224570, &amp;#43;0ns)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:Send(0x55b891224570)
&amp;#43;2.000000000s 0 UdpEchoClientApplication:Send(): [INFO ] At time &amp;#43;2s client sent 1024 bytes to 10.1.1.2 port 9
&amp;#43;2.003686400s 1 UdpEchoServerApplication:HandleRead(0x55b8911fcb10, 0x55b891230e70)
&amp;#43;2.003686400s 1 UdpEchoServerApplication:HandleRead(): [INFO ] At time &amp;#43;2.00369s server received 1024 bytes from 10.1.1.1 port 49153
&amp;#43;2.003686400s 1 UdpEchoServerApplication:HandleRead(): [LOGIC] Echoing packet
......&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&#34;记录日志&#34;&gt;记录日志
&lt;/h3&gt;&lt;p&gt;要将某个源文件划入某个模块，可以使用这个宏：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-8&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-8&#34; style=&#34;display:none;&#34;&gt;NS_LOG_COMPONENT_DEFINE(&amp;#34;ComponentName&amp;#34;);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;NS_LOG_COMPONENT_DEFINE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ComponentName&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;对于 &lt;code&gt;LOG_FUNCTION&lt;/code&gt; 级别的日志，可以使用 &lt;code&gt;NS_LOG_FUNCTION(this)&lt;/code&gt;（静态函数使用 &lt;code&gt;NS_LOG_FUNCTION_NOARGS()&lt;/code&gt;），它会在函数开始时打印函数名和参数，函数结束时打印函数名和返回值。而对于其他级别的日志，可以使用 &lt;code&gt;NS_LOG_&amp;lt;LEVEL&amp;gt;&lt;/code&gt;，如：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-9&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-9&#34; style=&#34;display:none;&#34;&gt;NS_LOG_INFO(&amp;#34;This is an info message&amp;#34;);
NS_LOG_DEBUG(&amp;#34;This is a debug message&amp;#34;);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;NS_LOG_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;This is an info message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;NS_LOG_DEBUG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;This is a debug message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&#34;命令参数&#34;&gt;命令参数
&lt;/h2&gt;&lt;p&gt;ns-3也有一个自带的命令行参数解析器，从而避免手动解析或使用第三方库的麻烦。在 &lt;code&gt;main&lt;/code&gt; 函数传入了 &lt;code&gt;argc&lt;/code&gt; 和 &lt;code&gt;argv&lt;/code&gt; 的情况下，可以使用 &lt;code&gt;CommandLine&lt;/code&gt; 类来解析命令行参数：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-10&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-10&#34; style=&#34;display:none;&#34;&gt;CommandLine cmd;
cmd.Parse(argc, argv);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;CommandLine&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;要使用 &lt;code&gt;ns3&lt;/code&gt; 工具运行时加入命令行参数，可以用下面两种等效的方式：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-11&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-11&#34; style=&#34;display:none;&#34;&gt;./ns3 run examples/tutorial/first.cc -- --PrintHelp
./ns3 run &amp;#34;examples/tutorial/first.cc --PrintHelp&amp;#34;&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./ns3 run examples/tutorial/first.cc -- --PrintHelp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./ns3 run &lt;span class=&#34;s2&#34;&gt;&amp;#34;examples/tutorial/first.cc --PrintHelp&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;当然直接加参数也问题不大，会提示更正的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;自带参数&#34;&gt;自带参数
&lt;/h3&gt;&lt;p&gt;这个参数解析器自带了一些参数，可以通过 &lt;code&gt;--PrintHelp&lt;/code&gt; 查看（竟然不是 &lt;code&gt;--help&lt;/code&gt;，奇怪）。比如 &lt;code&gt;--PrintAttributes=&amp;lt;TypeId&amp;gt;&lt;/code&gt; 可以查看某一类型附带的参数，以及各自的默认值。比如在第一个示例代码中，&lt;code&gt;PointToPointChannel&lt;/code&gt; 的默认参数为：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-12&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-12&#34; style=&#34;display:none;&#34;&gt;$ ./ns3 run examples/tutorial/first.cc -- --PrintAttributes=ns3::PointToPointChannel
Attributes for TypeId ns3::PointToPointChannel
    --ns3::PointToPointChannel::Delay=[&amp;#43;0ns]
        Propagation delay through the channel
Attributes defined in parent class ns3::Channel
    --ns3::Channel::Id=[0]
        The id (unique integer) of this Channel.&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./ns3 run examples/tutorial/first.cc -- --PrintAttributes&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;ns3::PointToPointChannel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Attributes &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; TypeId ns3::PointToPointChannel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    --ns3::PointToPointChannel::Delay&lt;span class=&#34;o&#34;&gt;=[&lt;/span&gt;+0ns&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Propagation delay through the channel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Attributes defined in parent class ns3::Channel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    --ns3::Channel::Id&lt;span class=&#34;o&#34;&gt;=[&lt;/span&gt;0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        The id &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;unique integer&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; of this Channel.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个和我们在文档中看到的是一致的，默认增加0ns的延迟，但在代码中增加了2ms，覆盖了默认值。但&lt;code&gt;--PrintHelp&lt;/code&gt; 并没有提到的是，也可以用命令行参数改变这些&lt;strong&gt;默认值&lt;/strong&gt;。比如，在删除代码中设置链路延迟的部分之后，可以使用以下参数将其值改为100ms：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-13&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-13&#34; style=&#34;display:none;&#34;&gt;./ns3 run examples/tutorial/first.cc -- --ns3::PointToPointChannel::Delay=100ms&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./ns3 run examples/tutorial/first.cc -- --ns3::PointToPointChannel::Delay&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;100ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;上面“改变默认值”可以理解为：对于一个属性值，设定的优先级为代码设定值&amp;gt;命令行参数设定值&amp;gt;默认值。更高的优先级会完全覆盖低优先级的值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;自定义参数&#34;&gt;自定义参数
&lt;/h3&gt;&lt;p&gt;当然也可以引入自定义的参数，通过 &lt;code&gt;cmd.AddValue&lt;/code&gt; 添加。比如在第一个示例代码中，添加一个 &lt;code&gt;--nPackets&lt;/code&gt; 参数，用于设置发送的数据包数量：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-14&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-14&#34; style=&#34;display:none;&#34;&gt;uint32_t nPackets = 1;
cmd.AddValue(&amp;#34;nPackets&amp;#34;, &amp;#34;Number of packets to send&amp;#34;, nPackets);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nPackets&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AddValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;nPackets&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Number of packets to send&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nPackets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;然后在后面设置 &lt;code&gt;MaxPackets&lt;/code&gt; attribute时传入 &lt;code&gt;nPackets&lt;/code&gt; 即可。这样也可以避开命令行参数优先级的问题。&lt;/p&gt;
&lt;h2 id=&#34;跟踪&#34;&gt;跟踪
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;模拟的全部目的是生成输出以供进一步研究，而ns-3跟踪系统是实现这一目标的主要机制。&lt;/p&gt;
&lt;p&gt;—— ns-3文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ns-3的跟踪功能，我划分为三个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跟踪源&lt;/strong&gt; (trace source)：在仿真的某些阶段触发，并发送某些内部数据（如数据包内容）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跟踪接收器&lt;/strong&gt; (trace sink)：接收跟踪源发出的数据&lt;/li&gt;
&lt;li&gt;前两者之间的连接&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将跟踪源和跟踪接收器分开，可以在不改变跟踪源的情况下，更改接收方式（如新增一个接收器）。在这篇开发者给出的教程中，将会使用一些自带的跟踪源和接收器；后面开发者还写了一篇更加详细的教程，以介绍更加复杂的跟踪用法。&lt;/p&gt;
&lt;h3 id=&#34;ascii跟踪&#34;&gt;ASCII跟踪
&lt;/h3&gt;&lt;p&gt;ns-3自带一个ASCII跟踪的helper以帮助设置，在前面第一个示例代码中，可以像这样修改：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-15&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-15&#34; style=&#34;display:none;&#34;&gt;AsciiTraceHelper ascii;
pointToPoint.EnableAsciiAll(ascii.CreateFileStream(&amp;#34;myfirst.tr&amp;#34;));
Simulator::Run();&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;AsciiTraceHelper&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pointToPoint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EnableAsciiAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CreateFileStream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;myfirst.tr&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Simulator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;然后重新运行一遍，你就会在shell的工作目录中看到一个 &lt;code&gt;myfirst.tr&lt;/code&gt; 文件。里面有6行一长串数据，我们拿出第一行，进行一下换行拆分：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;plaintext&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-16&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-16&#34; style=&#34;display:none;&#34;&gt;&amp;#43; 
2 
/NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue 
ns3::PppHeader (Point-to-Point Protocol: IP (0x0021)) 
ns3::Ipv4Header (tos 0x0 DSCP Default ECN Not-ECT ttl 64 id 0 protocol 17 offset (bytes) 0 flags [none] length: 1052 10.1.1.1 &amp;gt; 10.1.1.2) 
ns3::UdpHeader (length: 1032 49153 &amp;gt; 9) 
Payload (size=1024)&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+ 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ns3::PppHeader (Point-to-Point Protocol: IP (0x0021)) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ns3::Ipv4Header (tos 0x0 DSCP Default ECN Not-ECT ttl 64 id 0 protocol 17 offset (bytes) 0 flags [none] length: 1052 10.1.1.1 &amp;gt; 10.1.1.2) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ns3::UdpHeader (length: 1032 49153 &amp;gt; 9) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Payload (size=1024)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;第一行的 &lt;code&gt;+&lt;/code&gt; 代表入队操作。每条跟踪数据的第一个字符会有四种可能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt;：设备队列上入队&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;：设备队列上出队&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt;：丢包（dropped），可能是因为队列满了&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt;：从外部接收&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第二行的 &lt;code&gt;2&lt;/code&gt; 代表模拟进行时刻。第三行描述了该行为的发起者，即节点0上的设备0发送队列进行入队，也就是节点0准备发送数据了。后面的几行可以参照Internet的分层模型，分别是链路层的PPP头、网络层的IPv4头、传输层的UDP头和应用层的数据。&lt;/p&gt;
&lt;h3 id=&#34;pcap跟踪&#34;&gt;PCAP跟踪
&lt;/h3&gt;&lt;p&gt;PCAP相对上面的ASCII来说就友好多了，毕竟我们可以用Wireshark打开。类似于ASCII跟踪，PCAP跟踪可以这样应用于第一个示例代码：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-17&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-17&#34; style=&#34;display:none;&#34;&gt;pointToPoint.EnablePcapAll(&amp;#34;myfirst&amp;#34;);
Simulator::Run();&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pointToPoint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EnablePcapAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;myfirst&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Simulator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这次会在shell的工作目录下，对每个节点和网络设备生成一个 &lt;code&gt;pcap&lt;/code&gt; 文件。tcpdump的用法这里就不介绍了，Wireshark则可以直接打开，就像用它抓的包一样。&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/doxygen/d7/d2e/namespacens3.html#aa6464a4d69551a9cc968e17a65f39bdb&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.nsnam.org/docs/doxygen/d7/d2e/namespacens3.html#aa6464a4d69551a9cc968e17a65f39bdb&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
        </item>
        <item>
        <title>ns-3 入门 2：概念与第一个示例</title>
        <link>https://cyp0633.com/post/ns3-concepts/</link>
        <pubDate>Sat, 27 Jan 2024 22:57:00 +0800</pubDate>
        
        <guid>https://cyp0633.com/post/ns3-concepts/</guid>
        <description>&lt;p&gt;本文根据官方教程 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/tutorial/html/conceptual-overview.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Conceptual Overview&lt;/a&gt; 一章写成。在这章中，教程通过一个代码示例，演示了ns-3的几大基本概念及其基本使用方法。但是个人觉得顺序比较难懂，所以对其进行了一定程度的重新组织。&lt;/p&gt;
&lt;p&gt;下文中代码经过一点点修改，原代码见&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;，代码均以GPLv2发布。&lt;/p&gt;
&lt;h2 id=&#34;概念&#34;&gt;概念
&lt;/h2&gt;&lt;h3 id=&#34;节点-node&#34;&gt;节点 &lt;em&gt;Node&lt;/em&gt;
&lt;/h3&gt;&lt;p&gt;计算机网络可以抽象为一个图，而一个节点就是其中的一个网络设备。该抽象不考虑网络设备的内部结构与功能，所以路由器（3层）、交换机（2层）、计算机均抽象为节点。因此，节点本身没有任何功能，也不能直接连接任何信道，仅代表一个能收发数据的事物，功能需要作为应用实现，信道通过设备连接。&lt;/p&gt;
&lt;p&gt;节点使用 &lt;code&gt;ns3::Node&lt;/code&gt; 类表示，并由 &lt;code&gt;ns3::NodeContainer&lt;/code&gt; 类管理。要创建指定数量的节点，可以用 &lt;code&gt;Create&lt;/code&gt; 实例方法。以下代码创建了两个节点，并将其存储在 &lt;code&gt;nodes&lt;/code&gt; 中：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-0&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-0&#34; style=&#34;display:none;&#34;&gt;NodeContainer nodes;
nodes.Create(2);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;NodeContainer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;要使用下标访问 &lt;code&gt;NodeContainer&lt;/code&gt; 中的节点，可以用 &lt;code&gt;Get&lt;/code&gt; 实例方法。以下代码访问了第一个节点（下标从0开始）：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-1&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-1&#34; style=&#34;display:none;&#34;&gt;Ptr&amp;lt;Node&amp;gt; node = nodes.Get(0);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ptr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;上述代码中的 &lt;code&gt;Ptr&amp;lt;T&amp;gt;&lt;/code&gt; 是ns-3提供的智能指针，能够自动解引用，效果类似于 &lt;code&gt;std::shared_ptr&amp;lt;T&amp;gt;&lt;/code&gt;。类型 &lt;code&gt;T&lt;/code&gt; 必须支持 &lt;code&gt;Ref()&lt;/code&gt; 和 &lt;code&gt;Unref()&lt;/code&gt; 方法。关于ns-3的内存管理机制，请看 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/manual/html/object-model.html#memory-management-and-class-ptr&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;这一段&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了使光秃秃的节点具备一些基本的网络通信功能（实际上属于应用），可以使用 &lt;code&gt;ns3::InternetStackHelper&lt;/code&gt; 安装网络栈（包含TCP、UDP、IP等）。一个helper可以一次安装一整个 &lt;code&gt;NodeContainer&lt;/code&gt;，如以下代码将 &lt;code&gt;nodes&lt;/code&gt; 中的所有节点安装网络栈：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-2&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-2&#34; style=&#34;display:none;&#34;&gt;InternetStackHelper stack;
stack.Install(nodes);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;InternetStackHelper&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;stack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;由于并没有变量上的依赖关系，缺少网络栈并不会造成编译失败，但以示例代码为例，缺少网络栈会导致运行时创建更上层的应用失败，从而直接抛出SIGABRT。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;网络设备-net-device&#34;&gt;网络设备 &lt;em&gt;Net Device&lt;/em&gt;
&lt;/h3&gt;&lt;p&gt;正如电脑要上网就得插网卡（NIC）一样，节点要连接在一起，网络设备是不可或缺的。ns-3中的网络设备抽象包含了网卡的硬件功能和驱动程序功能，每个节点可以连接多个网络设备，用于连接多个不同的信道。&lt;/p&gt;
&lt;p&gt;网络设备使用 &lt;code&gt;ns3::NetDevice&lt;/code&gt; 类表示，并使用 &lt;code&gt;ns3::NetDeviceContainer&lt;/code&gt; 进行管理。同样正如网卡分为有线和无线网卡一样，实际使用时多选择其子类，如以太网使用的 &lt;code&gt;ns3::CsmaNetDevice&lt;/code&gt; 类，以及Wi-Fi使用的 &lt;code&gt;ns3::WifiNetDevice&lt;/code&gt; 类。在该篇示例代码中，由helper总揽网络设备和信道的创建，此处按下不表。&lt;/p&gt;
&lt;p&gt;给网络设备分配IPv4地址后，可以将其看作一个接口。使用 &lt;code&gt;ns3::Ipv4AddressHelper&lt;/code&gt; 类，可以为一个网络设备分配一个IPv4地址。以下代码设置了IP地址分配范围和掩码，并将其按顺序分配给一个 &lt;code&gt;NetDeviceContainer&lt;/code&gt; 中的设备，返回的是一个接口容器 &lt;code&gt;ns3::Ipv4InterfaceContainer&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-3&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-3&#34; style=&#34;display:none;&#34;&gt;Ipv4AddressHelper address;
address.SetBase(&amp;#34;10.1.1.0&amp;#34;, &amp;#34;255.255.255.0&amp;#34;);
Ipv4InterfaceContainer interfaces = address.Assign(devices);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ipv4AddressHelper&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetBase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;10.1.1.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;255.255.255.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ipv4InterfaceContainer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;interfaces&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Assign&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;此处使用了多个隐式转换，从 &lt;code&gt;const char*&lt;/code&gt; 即字符串描述的地址到 &lt;code&gt;Ipv4Address&lt;/code&gt; 和 &lt;code&gt;Ipv4Mask&lt;/code&gt;。如果不希望从10.1.1.1开始分配，可以使用第三个参数 &lt;code&gt;base&lt;/code&gt;，如 &amp;ldquo;0.0.0.3&amp;rdquo; 表示从10.1.1.3开始分配&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;信道-channel&#34;&gt;信道 &lt;em&gt;Channel&lt;/em&gt;
&lt;/h3&gt;&lt;p&gt;信道代表节点之间的连接，比如RJ45双绞线，比如Wi-Fi，都可以抽象为信道。&lt;/p&gt;
&lt;p&gt;信道使用 &lt;code&gt;ns3::Channel&lt;/code&gt; 类表示，并由 &lt;code&gt;ns3::ChannelContainer&lt;/code&gt; 类管理。同样，信道也有多种类型，如以太网使用的 &lt;code&gt;ns3::CsmaChannel&lt;/code&gt; 类，Wi-Fi使用的 &lt;code&gt;ns3::WifiChannel&lt;/code&gt; 类。但是在本篇示例代码中，并没有明确地使用 &lt;code&gt;Channel&lt;/code&gt;，而是借助了网络设备和信道的紧密联系，由helper类统一创建。比如在下面的代码中，新建了一个点对点信道，设置两端网络设备传输速率为5 Mbps，信道延迟2 ms，并将其安装到一个 &lt;code&gt;NodeContainer&lt;/code&gt; 中，最终返回创建完成的网络设备 &lt;code&gt;NetDeviceContainer&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-4&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-4&#34; style=&#34;display:none;&#34;&gt;PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute(&amp;#34;DataRate&amp;#34;, StringValue(&amp;#34;5Mbps&amp;#34;));
pointToPoint.SetChannelAttribute(&amp;#34;Delay&amp;#34;, StringValue(&amp;#34;2ms&amp;#34;));
auto devices = pointToPoint.Install(nodes);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;PointToPointHelper&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pointToPoint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pointToPoint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetDeviceAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;DataRate&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;5Mbps&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pointToPoint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetChannelAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Delay&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;2ms&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;devices&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pointToPoint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;属性（attribute）相比于普通的成员变量，具有更多的控制，如可以设置默认值（包括编译期和运行期）、边界检查等。关于更多属性信息，请看 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/manual/html/attributes.html#id1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;这一段&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;点对点信道限制输入的 &lt;code&gt;NodeContainer&lt;/code&gt; 必须有且仅有两个节点，否则运行时会抛出异常。&lt;/p&gt;
&lt;p&gt;这里设置的网络设备属性和信道属性，应该参考具体的网络设备&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;和信道类&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;的文档。&lt;/p&gt;
&lt;p&gt;信道的延迟，就是propagation delay。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;应用-application&#34;&gt;应用 &lt;em&gt;Application&lt;/em&gt;
&lt;/h3&gt;&lt;p&gt;节点的实际功能均由应用实现。这是一个庞大的概念，不仅仅包含应用层的内容，也同时包含了传输层、网络层等内容。它描述了某个节点的行为。&lt;/p&gt;
&lt;p&gt;应用使用 &lt;code&gt;ns3::Application&lt;/code&gt; 类表示，并由 &lt;code&gt;ApplicationContainer&lt;/code&gt; 类管理。该container的具体创建由具体的应用程序实现。使用 &lt;code&gt;Start&lt;/code&gt; 和 &lt;code&gt;Stop&lt;/code&gt; 实例方法，可以控制应用的开始结束时间，仿真程序在所有应用运行结束之前不会主动停止：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-5&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-5&#34; style=&#34;display:none;&#34;&gt;ApplicationContainer serverApps = xxx;
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ApplicationContainer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;serverApps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xxx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;serverApps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;serverApps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在示例代码中，具体使用了 &lt;code&gt;ns3::UdpEchoClientApplication&lt;/code&gt; 和 &lt;code&gt;ns3::UdpEchoServerApplication&lt;/code&gt; 类，作用应该不言而喻。&lt;code&gt;UdpEchoServerApplication&lt;/code&gt; 使用 &lt;code&gt;ns3::UdpEchoServerHelper&lt;/code&gt; 类创建，如以下代码在第二个节点上安装，设置端口为9，并在1-10s运行：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-6&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-6&#34; style=&#34;display:none;&#34;&gt;UdpEchoServerHelper echoServer(9);
ApplicationContainer serverApps = echoServer.Install(nodes.Get(1));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UdpEchoServerHelper&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;echoServer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ApplicationContainer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;serverApps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;echoServer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;serverApps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;serverApps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;这里包含一个隐式转换。&lt;code&gt;nodes.Get(1)&lt;/code&gt; 返回的是 &lt;code&gt;Ptr&amp;lt;Node&amp;gt;&lt;/code&gt;，而 &lt;code&gt;Install&lt;/code&gt; 方法接受的是 &lt;code&gt;NodeContainer&lt;/code&gt;，但是 &lt;code&gt;Ptr&amp;lt;Node&amp;gt;&lt;/code&gt; 可以隐式转换为 &lt;code&gt;NodeContainer&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;负责主动发送数据的 &lt;code&gt;UdpEchoClientApplication&lt;/code&gt; 与上文的helper类似，但有更多的参数可供自定义。如以下代码，将第二个节点的端口9作为目标，设置发送间隔为1s、包大小为1024B、发送总数为1&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;，安装到第一个节点上，并在2-10s运行：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-7&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-7&#34; style=&#34;display:none;&#34;&gt;UdpEchoClientHelper echoClient(interfaces.GetAddress(1), 9);
echoClient.SetAttribute(&amp;#34;MaxPackets&amp;#34;, UintegerValue(1));
echoClient.SetAttribute(&amp;#34;Interval&amp;#34;, TimeValue(Seconds(1.0)));
echoClient.SetAttribute(&amp;#34;PacketSize&amp;#34;, UintegerValue(1024));
ApplicationContainer clientApps = echoClient.Install(nodes.Get(0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UdpEchoClientHelper&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;echoClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interfaces&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetAddress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;echoClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;MaxPackets&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UintegerValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;echoClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Interval&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TimeValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;echoClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;PacketSize&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UintegerValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ApplicationContainer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clientApps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;echoClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;clientApps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;clientApps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&#34;代码示例&#34;&gt;代码示例
&lt;/h2&gt;&lt;p&gt;使用ns-3编写的仿真器程序是声明式而非命令式的，这有点类似于前端工程中兴起的类似概念。&lt;/p&gt;
&lt;h3 id=&#34;头文件&#34;&gt;头文件
&lt;/h3&gt;&lt;p&gt;ns-3提供了一些大粒度的头文件，可以一定程度上免去繁琐的找头文件过程。下面头文件的内容，基本就是示例代码中用到的模块。&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-8&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-8&#34; style=&#34;display:none;&#34;&gt;#include &amp;#34;ns3/core-module.h&amp;#34;
#include &amp;#34;ns3/network-module.h&amp;#34;
#include &amp;#34;ns3/internet-module.h&amp;#34;
#include &amp;#34;ns3/point-to-point-module.h&amp;#34;
#include &amp;#34;ns3/applications-module.h&amp;#34;&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;ns3/core-module.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;ns3/network-module.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;ns3/internet-module.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;ns3/point-to-point-module.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;ns3/applications-module.h&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&#34;日志&#34;&gt;日志
&lt;/h3&gt;&lt;p&gt;ns-3的日志是可以按照模块自定义的，当然这也需要自行为代码划分模块。如示例代码中的这一行macro就是将当前源文件划分到 &lt;code&gt;FirstScriptExample&lt;/code&gt; 模块：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-9&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-9&#34; style=&#34;display:none;&#34;&gt;ns3::NS_LOG_COMPONENT_DEFINE(&amp;#34;FirstScriptExample&amp;#34;);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ns3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NS_LOG_COMPONENT_DEFINE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;FirstScriptExample&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果需要控制日志的详细程度，可以使用（如将 &lt;code&gt;UdpEchoClientApplication&lt;/code&gt; 的日志级别设为 &lt;code&gt;INFO&lt;/code&gt;）&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-10&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-10&#34; style=&#34;display:none;&#34;&gt;ns3::LogComponentEnable(&amp;#34;UdpEchoClientApplication&amp;#34;, LOG_LEVEL_INFO);&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ns3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LogComponentEnable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;UdpEchoClientApplication&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOG_LEVEL_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&#34;命名空间&#34;&gt;命名空间
&lt;/h3&gt;&lt;p&gt;正如上文提到的，本代码示例中使用的类几乎均在 &lt;code&gt;ns3&lt;/code&gt; 命名空间下。&lt;/p&gt;
&lt;h3 id=&#34;模拟器&#34;&gt;模拟器
&lt;/h3&gt;&lt;p&gt;当上文模拟器所需执行的行为全部描述完毕后，就需要调用模拟器进行模拟了。这个示例代码的模拟是有穷尽的，所以可以等待模拟自行结束，然后直接销毁：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-11&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-11&#34; style=&#34;display:none;&#34;&gt;Simulator::Run();
Simulator::Destroy();&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Simulator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Simulator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Destroy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;但是，如果模拟永远不会结束，或是希望自定义一个结束时间，则需要在 &lt;code&gt;Run()&lt;/code&gt; &lt;strong&gt;之前&lt;/strong&gt;调用 &lt;code&gt;Stop()&lt;/code&gt;，如以下代码将模拟时间限制在10s：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;cpp&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-12&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-12&#34; style=&#34;display:none;&#34;&gt;Simulator::Stop(Seconds(10.0));
Simulator::Run();
Simulator::Destroy();&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Simulator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Seconds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Simulator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Simulator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Destroy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&#34;编译&#34;&gt;编译
&lt;/h3&gt;&lt;p&gt;教程中提到的 &lt;code&gt;./ns3 build&lt;/code&gt; &lt;strong&gt;大概率是错的&lt;/strong&gt;，个人猜测是之前 &lt;code&gt;./waf&lt;/code&gt; 直接查找替换后的产物&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;。现在不必将文件移至 &lt;code&gt;scratch/&lt;/code&gt; 中，如本例子可以直接执行：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-13&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-13&#34; style=&#34;display:none;&#34;&gt;./ns3 run examples/tutorial/first.cc&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./ns3 run examples/tutorial/first.cc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/nsnam/ns-3-dev/-/blob/61750bbd89ee258a423a7ec095b13896eeab47c5/examples/tutorial/first.cc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://gitlab.com/nsnam/ns-3-dev/-/blob/61750bbd89ee258a423a7ec095b13896eeab47c5/examples/tutorial/first.cc&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/doxygen/d5/d4f/classns3_1_1_ipv4_address_helper.html#acf7b16dd25bac67e00f5e25f90a9a035&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.nsnam.org/docs/doxygen/d5/d4f/classns3_1_1_ipv4_address_helper.html#acf7b16dd25bac67e00f5e25f90a9a035&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/doxygen/dc/d89/classns3_1_1_point_to_point_net_device.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.nsnam.org/docs/doxygen/dc/d89/classns3_1_1_point_to_point_net_device.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/doxygen/db/d4a/classns3_1_1_point_to_point_channel.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.nsnam.org/docs/doxygen/db/d4a/classns3_1_1_point_to_point_channel.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/doxygen/d4/d0c/classns3_1_1_udp_echo_client.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.nsnam.org/docs/doxygen/d4/d0c/classns3_1_1_udp_echo_client.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/nsnam/ns-3-dev/-/commit/3c604d5b2e57850c3db611709c0c04be8c59c044?page=3#085fdec380970f024611fd48e61bfbcdfa826a5d_846_846&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://gitlab.com/nsnam/ns-3-dev/-/commit/3c604d5b2e57850c3db611709c0c04be8c59c044?page=3#085fdec380970f024611fd48e61bfbcdfa826a5d_846_846&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
        </item>
        <item>
        <title>ns-3 入门 1：介绍与安装</title>
        <link>https://cyp0633.com/post/ns3-intro-installation/</link>
        <pubDate>Fri, 26 Jan 2024 22:57:00 +0800</pubDate>
        
        <guid>https://cyp0633.com/post/ns3-intro-installation/</guid>
        <description>&lt;p&gt;根据官方教程 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/tutorial/html/getting-started.html#overview&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Getting Started&lt;/a&gt; 一章写成。&lt;/p&gt;
&lt;h2 id=&#34;介绍&#34;&gt;介绍
&lt;/h2&gt;&lt;p&gt;ns-3是一个离散网络事件模拟器。不难理解这个描述：比如改变拥塞窗口大小，发出数据包，都是离散事件。将这些离散事件按发生时间顺序模拟，就能得到这个系统在一段时间内的运行过程。因为计算机网络（也有其他一些类似系统）的运行过程是离散的，而不像往水池里倒水那样连续的，所以这种模拟方法是合理的。&lt;/p&gt;
&lt;p&gt;ns-3本质上是一组库，可以在C++（或Python，但之后忽略）程序中导入，也就是自己写代码把ns-3提供的工具串成一个完整的模拟程序。通过手动导入头文件和链接库，当然也可以直接利用ns-3编译出需要的程序，但ns-3也提供了 &lt;code&gt;ns3&lt;/code&gt; 命令行工具，以构建并运行模拟源代码。&lt;/p&gt;
&lt;h2 id=&#34;下载&#34;&gt;下载
&lt;/h2&gt;&lt;p&gt;ns-3的分发形式是源代码，无论发行版是否有打包，都推荐使用源代码安装。以下仅以Linux为例，Windows用户自觉去装WSL2。&lt;/p&gt;
&lt;p&gt;如果你使用Ubuntu，则可以参考官方文档的对应部分&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;先按需安装好依赖；如果你和我一样使用的是Arch Linux，那么有一个 &lt;a class=&#34;link&#34; href=&#34;https://aur.archlinux.org/packages/ns3?all_deps=1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;em&gt;&lt;strong&gt;PROTECTED_0&lt;/strong&gt;&lt;/em&gt; AUR 包&lt;/a&gt;。但个人不建议你直接装它，因为上文提到的 &lt;code&gt;ns3&lt;/code&gt; 命令行工具会留在源代码目录里，无法直接引用。所以可以利用AUR装依赖。&lt;strong&gt;Arch Linux的cppyy（用于写Python仿真程序）已更新至3.x，ns-3还没跟上支持，如有需要请注意。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;然后从官网下载 &lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/releases/latest/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;最新源码包&lt;/a&gt;，解压，进入里面的 &lt;code&gt;ns-3.xx&lt;/code&gt; 目录。下文均基于3.40版本，此处暂时不提另外两种使用Bake和Git的方法。&lt;/p&gt;
&lt;h2 id=&#34;编译&#34;&gt;编译
&lt;/h2&gt;&lt;p&gt;官方在文档里给了三种编译方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;build.py&lt;/code&gt;：比较简单，但不太自由&lt;/li&gt;
&lt;li&gt;使用CMake：能自定义编译的模块，以及一些额外的选项&lt;/li&gt;
&lt;li&gt;使用Bake：好处就是可以包揽从下载到安装&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;个人需要在之后将ns-3安装至系统目录，而其限定只能用第二种方法，所以下面只写第二种。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ns3&lt;/code&gt; 命令行工具也可以作为CMake的一个wrapper。在 &lt;code&gt;ns-allinone-3.xx/ns-3.xx&lt;/code&gt; 目录中，运行以下命令：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-0&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-0&#34; style=&#34;display:none;&#34;&gt;./ns3 clean
./ns3 configure --enable-tests --enable-examples --prefix=/usr/local
./ns3 build&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./ns3 clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./ns3 configure --enable-tests --enable-examples --prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./ns3 build&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其中 &lt;code&gt;configure&lt;/code&gt; 的前两个参数是一起编译测试和示例，&lt;code&gt;--prefix&lt;/code&gt; 指定之后的安装路径。完整的参数列表可以使用 &lt;code&gt;./ns3 configure --help&lt;/code&gt; 查看。&lt;/p&gt;
&lt;p&gt;还需要注意configure完成后显示的build profile。如果在之后使用时需要使用GDB调试，则需确保其为 &lt;code&gt;debug&lt;/code&gt; （加入 &lt;code&gt;-d debug&lt;/code&gt;参数并重新编译），如不需调试，则可以使用默认的 &lt;code&gt;optimized&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;只要不是缺少非必需的依赖，编译都会正常进行。CMake也会输出各个模块是否会被编译，以及不被编译的原因（如果有；如缺少依赖，或用户指定不编译）。官方文档中有示例的编译输出，可以结合来看。&lt;/p&gt;
&lt;p&gt;编译完成后，可以运行测试：&lt;/p&gt;
&lt;div class=&#34;codeblock&#34;&gt;
    &lt;header&gt;
        &lt;span class=&#34;codeblock-lang&#34;&gt;bash&lt;/span&gt;
        &lt;button 
            class=&#34;codeblock-copy&#34;
            data-id=&#34;codeblock-id-1&#34;
            data-copied-text=&#34;已复制！&#34;
        &gt;
            复制代码
        &lt;/button&gt;
    &lt;/header&gt;
    &lt;code id=&#34;codeblock-id-1&#34; style=&#34;display:none;&#34;&gt;./test.py&lt;/code&gt;&lt;div class=&#34;&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./test.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;到这里编译过程就结束了。由于 &lt;code&gt;ns3&lt;/code&gt; 命令行工具的存在，写程序时不需要太关注库和头文件的位置，同时为了防止多个ns-3版本共存冲突，开发者声称大部分人并不需要安装了：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Most users do not install ns-3 libraries to typical system library directories; they instead just leave the libraries in the build directory, and the ns3 Python program will find these libraries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;安装&#34;&gt;安装
&lt;/h2&gt;&lt;p&gt;虽然 &lt;code&gt;ns3&lt;/code&gt; 命令行工具能够帮助构建系统找到头文件和链接库，但麻烦的是IDE并不这么认为（clangd自定义就比较麻烦），所以我决定将其安装到系统目录中。前面提到我添加了 &lt;code&gt;--prefix=/usr/local&lt;/code&gt;，在这一步ns-3的头文件和链接库就会被分别安装到 &lt;code&gt;/usr/local/include/ns3&lt;/code&gt; 和 &lt;code&gt;/usr/local/lib&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;根据文档，安装也需使用 &lt;code&gt;ns3&lt;/code&gt; 命令行。但是 &lt;code&gt;ns3&lt;/code&gt; 命令行工具会故意阻止以root权限执行，确有需要的可以编辑其约1400行处，删掉对 &lt;code&gt;refuse_run_as_root()&lt;/code&gt; 的调用&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;。但也有副作用，比如之后每次构建运行仿真程序都要输入密码。在此希望读者也能够对自己的目的和行为有明确的认知。&lt;/p&gt;
&lt;p&gt;然后，执行 &lt;code&gt;./ns3 install&lt;/code&gt; 即可将ns-3的头文件和链接库安装至prefix指定的位置。&lt;/p&gt;
&lt;p&gt;如果只是为了IDE识别，当然也有另外一种方法，仅把头文件复制到系统目录中。头文件就在 &lt;code&gt;build/include/ns3&lt;/code&gt; 目录中。&lt;/p&gt;
&lt;p&gt;安装完成后，下一篇将顺着官方教程的脉络，认识一个仿真程序的示例。&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/installation/html/linux.html#requirements&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.nsnam.org/docs/installation/html/linux.html#requirements&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.nsnam.org/docs/installation/html/quick-start.html#installing-ns-3&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.nsnam.org/docs/installation/html/quick-start.html#installing-ns-3&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
        </item>
        
    </channel>
</rss>
