NS3:FlowMonitor设计讲解 和 路由协议控制开销分析 代码 (tr文件分析 和 wireshark分析)

NS3:FlowMonitor设计讲解 和 路由协议控制开销分析 代码 (tr文件分析 和 wireshark分析)

需要注意的是 FlowMonitor对广播流不起作用

flowmonitor的监控形式是 点对点,因为其定义的时候是需要目的ip的。所以它就不能跟踪广播的ip包。 olsr的控制包是广播包,所以不能跟踪olsr的控制包。博文的第二部分,添加了怎么统计路由协议的控制包,可以用 .tr文件,逐行读取 以 t 开头的,以及含有 路由协议包头的条目计数即可。就是路由协议发出的控制包的个数,含有payload就是发出的数据包的个数。 第二种方式是,生成pcap文件,合并所有的pacp文件以后,用wireshark分析包的数量,博文中给出了示例。两种方法都更给出了代码, 第一种使用更方便。

各有关类的描述与说明

  • 每个仿真只有一个FlowMonitor(后面会做详细解释)

  • 每个仿真只有一个FlowClassifier

    • 每个流分配唯一的整数标识
    • 包含映射参数的分类方法(例如,分组或分组报头)到相应的流标识符;
    • FlowClassifier是抽象的,需要一个具体的子类

      Ipv4FlowClassifier

  • 通常(但不一定)一个节点上一个流探针FlowProbe

    • 负责获取分组数据
    • 与FlowClassifier合作
    • FlowProbe是抽象的,需要一个具体的子类

      Ipv4FlowProbe

      • Ipv4FlowProbe需要一个匹配的分类器 Ipv4FlowClassifier
  • 每个FlowProbe的每个模拟流程对应一个ProbeFlowStats对象来统计从第一次探测直到此时探测中接收到数据包的信息

    • 按FlowId索引
    • 字节数
    • 分组数
    • 延时
  • 每个FlowMonitor的每个流对应一个EndToEndFlowStats,记录了

    • 丢包数
    • 丢字节数
    • 总字节数
    • 总包数
    • 端到端延时

FlowMonitor模块详解

模块描述

Flow Monitor模块的目标是提供一个灵活的系统来衡量网络协议的性能。 该模块使用安装在网络节点中的探针来跟踪节点交换的数据包,并进行测量一些参数。 数据包根据它们所属的流进行划分,其中每个流根据探测器的特征定义(例如,对于IP包,数据被定义为五元组)

  • 协议
  • 源IP
  • 源端口
  • 目的IP
  • 目的端口

收集每个流的统计信息可以以XML格式导出。 此外,用户可以直接访问探针以请求关于每个流的特定统计数据。

设计

Flow Monitor模块采用模块化设计。 它可以通过继承ns3 :: FlowProbens3 :: FlowClassifier进行扩展。[FlowMonitor ]中描述了完整的模块设计。

适用范围和限制

目前,探针和分类器可用于IPv4和IPv6,每个探针将对分组进行跟踪和分类:

  • 发送数据包 (SendOutgoing IPv[4,6] 跟踪)
  • 转发数据包 (UnicastForward IPv[4,6] 跟踪)
  • 收到数据包 (LocalDeliver IPv[4,6] 跟踪)
  • 丢弃数据包(Drop IPv[4,6] 跟踪)

有关标签ns3::Ipv[4,6]FlowProbeTag将被添加到数据包中,基本数据包的数据将携带标签传输,这样可对数据包进行分类。

注意:因为在IP级别跟踪分组,探针将L4协议(例如,TCP)引起的重传作为新分组; 目前只对L4(TCP,UDP)数据包分类;只有单播数据包将被分类,这些限制可能在将来被删除。

为每个流收集的数据是:

  • timeFirstTxPacket: 传输流中第一个数据包时的时间
  • timeLastTxPacket:传输 流中最后一个数据包时的时间
  • timeFirstRxPacket:端节点接收到流中的第一个数据包的时间;
  • timeLastRxPacket: 收到流中的最后一个数据包的时间
  • delaySum: 所有收到的流数据包的所有端到端延迟的总和;
  • jitterSum:所有接收到的流数据包的所有端到端延迟抖动(延迟变化)值的总和,参考文档:rfc:3393;
  • txBytes, txPackets: 流的传输字节/数据包总数;
  • rxBytes, rxPackets: 流的接收字节/数据包总数;
  • lostPackets: 假设丢失的数据包总数(未报告超过10秒);
  • timesForwarded: 报告转发数据包的次数;
  • delayHistogram, jitterHistogram, packetSizeHistogram: 延迟,抖动和数据包大小的直方图
  • packetsDropped, bytesDropped: 丢失的数据包和字节数,根据丢失原因代码(在探测中定义)进行划分。

注意:探针测量的是包括IP头的包字节,L2标头有关信息不包含在度量范围内。

用例

用法::

 // Flow monitor
  Ptr<FlowMonitor> flowMonitor;
  FlowMonitorHelper flowHelper;
  flowMonitor = flowHelper.InstallAll();

  Simulator::Stop (Seconds(stop_time));
  Simulator::Run ();

  flowMonitor->SerializeToXmlFile("NameOfFile.xml", true, true);

SerializeToXmlFile()第二第三个参数分别用于激活/停用直方图和每探针详细统计数据,其他可能的替代方案可以在Doxygen文档中找到。

有关助手

助手类:ns3 :: FlowMonitorHelper 在main中只实例化一次
此外助手API遵循普通助手的模式使用。通过帮助程序,您可以在节点中安装监视器,设置监视器属性并打印统计信息。

属性设置

ns3::FlowMonitor 类中有一下属性:

  • MaxPerHopDelay (Time, default 10s): 应考虑的最大每跳延迟;
  • StartTime (Time, default 0s): 监控开始的时间;
  • DelayBinWidth (double, default 0.001): 延迟直方图中使用的宽度;
  • JitterBinWidth (double, default 0.001): 抖动直方图中使用的宽度;
  • PacketSizeBinWidth (double, default 20.0): 分组直方图中使用的宽度;
  • FlowInterruptionsBinWidth (double, default 0.25): 流终端直方图中使用的宽度;
  • FlowInterruptionsMinTime (double, default 0.5): 最小到达间隔时间被视为流量中断。

有关输出

主要的输出是关于流统计信息的XML格式的报告。 一个例子是::

  <?xml version="1.0" ?>
  <FlowMonitor>
    <FlowStats>
    <Flow flowId="1" timeFirstTxPacket="+0.0ns" timeFirstRxPacket="+20067198.0ns" timeLastTxPacket="+2235764408.0ns" timeLastRxPacket="+2255831606.0ns" delaySum="+138731526300.0ns" jitterSum="+1849692150.0ns" lastDelay="+20067198.0ns" txBytes="2149400" rxBytes="2149400" txPackets="3735" rxPackets="3735" lostPackets="0" timesForwarded="7466">
    </Flow>
    </FlowStats>
    <Ipv4FlowClassifier>
    <Flow flowId="1" sourceAddress="10.1.3.1" destinationAddress="10.1.2.2" protocol="6" sourcePort="49153" destinationPort="50000" />
    </Ipv4FlowClassifier>
    <Ipv6FlowClassifier>
    </Ipv6FlowClassifier>
    <FlowProbes>
    <FlowProbe index="0">
      <FlowStats  flowId="1" packets="3735" bytes="2149400" delayFromFirstProbeSum="+0.0ns" >
      </FlowStats>
    </FlowProbe>
    <FlowProbe index="2">
      <FlowStats  flowId="1" packets="7466" bytes="2224020" delayFromFirstProbeSum="+199415389258.0ns" >
      </FlowStats>
    </FlowProbe>
    <FlowProbe index="4">
      <FlowStats  flowId="1" packets="3735" bytes="2149400" delayFromFirstProbeSum="+138731526300.0ns" >
      </FlowStats>
    </FlowProbe>
    </FlowProbes>
  </FlowMonitor>

输出是由从10.1.3.1到10.1.2.2的TCP流生成的。

协议的代表含义(TCP/UDP, AODV/OLSR)

protocol=“6” 代表TCP
protocol=“17” 代表UDP
对于协议的 Port:654 代表 AODV ; 698 OLSR

值得注意的是,索引2探测器报告的数据包和其他探测器的字节数更多。
这是一种完全正常的行为,因为数据包在该节点的IP级别被分段。

还应该观察到接收节点的探测(索引4)不计算片段,因为重组在探测点之前完成。

已经有的使用的例子

src/flow-monitor/examples
此外,以下示例使用流量监视器的模块:

  • examples/matrix-topology/matrix-topology.cc
  • examples/routing/manet-routing-compare.cc
  • examples/routing/simple-global-routing.cc
  • examples/tcp/tcp-variants-comparison.cc
  • examples/wireless/multirate.cc
  • examples/wireless/wifi-hidden-terminal.cc

故障排除

不要在模拟中定义多个:ns3 :: FlowMonitorHelper

ns-3.34/examples/matrix-topology/matrix-topology.cc 出现 indefined reference

build/../examples/matrix-topology/matrix-topology.cc:297:对‘ns3::FlowMonitorHelper::FlowMonitorHelper()’未定义的引用
build/../examples/matrix-topology/matrix-topology.cc:298:对‘ns3::FlowMonitorHelper::InstallAll()’未定义的引用
build/../examples/matrix-topology/matrix-topology.cc:307:对‘ns3::FlowMonitor::SerializeToXmlFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, bool)’未定义的引用
build/../examples/matrix-topology/matrix-topology.cc:297:对‘ns3::FlowMonitorHelper::~FlowMonitorHelper()’未定义的引用
build/../examples/matrix-topology/matrix-topology.cc:297:对‘ns3::FlowMonitorHelper::~FlowMonitorHelper()’未定义的引用
  • 引入头文件:
#include "ns3/flow-monitor-module.h"
//#include "ns3/flow-monitor.h"
//#include "ns3/flow-monitor-helper.h"
  • 在example/matrix-topology/wscript 修改:
def build(bld):
    obj = bld.create_ns3_program('matrix-topology',
                                 ['network', 'internet', 'netanim', 'point-to-point', 'mobility', 'applications','flow-monitor'])
    obj.source = 'matrix-topology.cc'

示例代码

代码可直接查看这篇ns3利用FlowMonitor进行网络性能分析

FlowMonitor实例的分析文件:manet-routing-compare.cc

#include "ns3/flow-monitor-helper.h" //头文件加上

  Ptr<FlowMonitor> flowmon;
  FlowMonitorHelper flowmonHelper;
  flowmon = flowmonHelper.InstallAll ();
  NS_LOG_INFO ("Run Simulation.");
  CheckThroughput ();
  Simulator::Stop (Seconds (TotalTime));
  Simulator::Run ();

  flowmon->SerializeToXmlFile ((tr_name + ".flowmon").c_str(), false, false);
 // flowmon->SerializeToXmlFile ((tr_name + "HestandProbes.flowmon").c_str(), true, true);// 开启每个probe和直方图

  Simulator::Destroy ();
}


同时在FlowMonitor模块的example下面有:
wifi-olsr-flowmon.py 用python运行协议是UPD+OLSR
那么还有一个生成的xml文件的解析的 flowmon-parse-results.py 里面可以看到解析的 6: ‘TCP’, 17: ‘UDP’

from __future__ import division
import sys
import os
try:
    from xml.etree import cElementTree as ElementTree
except ImportError:
    from xml.etree import ElementTree

def parse_time_ns(tm):
    if tm.endswith('ns'):
        return float(tm[:-2])
    raise ValueError(tm)



## FiveTuple
class FiveTuple(object):
    ## class variables
    ## @var sourceAddress 
    #  source address
    ## @var destinationAddress 
    #  destination address
    ## @var protocol 
    #  network protocol
    ## @var sourcePort 
    #  source port
    ## @var destinationPort 
    #  destination port
    ## @var __slots_ 
    #  class variable list
    __slots_ = ['sourceAddress', 'destinationAddress', 'protocol', 'sourcePort', 'destinationPort']
    def __init__(self, el):
        '''! The initializer.
        @param self The object pointer.
        @param el The element.
        '''
        self.sourceAddress = el.get('sourceAddress')
        self.destinationAddress = el.get('destinationAddress')
        self.sourcePort = int(el.get('sourcePort'))
        self.destinationPort = int(el.get('destinationPort'))
        self.protocol = int(el.get('protocol'))
        
## Histogram
class Histogram(object):
    ## class variables
    ## @var bins
    #  histogram bins
    ## @var nbins
    #  number of bins
    ## @var number_of_flows
    #  number of flows
    ## @var __slots_
    #  class variable list
    __slots_ = 'bins', 'nbins', 'number_of_flows'
    def __init__(self, el=None):
        '''! The initializer.
        @param self The object pointer.
        @param el The element.
        '''
        self.bins = []
        if el is not None:
            #self.nbins = int(el.get('nBins'))
            for bin in el.findall('bin'):
                self.bins.append( (float(bin.get("start")), float(bin.get("width")), int(bin.get("count"))) )

## Flow
class Flow(object):
    ## class variables
    ## @var flowId
    #  delay ID
    ## @var delayMean
    #  mean delay
    ## @var packetLossRatio
    #  packet loss ratio
    ## @var rxBitrate
    #  receive bit rate
    ## @var txBitrate
    #  transmit bit rate
    ## @var fiveTuple
    #  five tuple
    ## @var packetSizeMean
    #  packet size mean
    ## @var probe_stats_unsorted
    #  unsirted probe stats
    ## @var hopCount
    #  hop count
    ## @var flowInterruptionsHistogram
    #  flow histogram
    ## @var rx_duration
    #  receive duration
    ## @var __slots_
    #  class variable list
    __slots_ = ['flowId', 'delayMean', 'packetLossRatio', 'rxBitrate', 'txBitrate',
                'fiveTuple', 'packetSizeMean', 'probe_stats_unsorted',
                'hopCount', 'flowInterruptionsHistogram', 'rx_duration']
    def __init__(self, flow_el):
        '''! The initializer.
        @param self The object pointer.
        @param flow_el The element.
        '''
        self.flowId = int(flow_el.get('flowId'))
        rxPackets = float(flow_el.get('rxPackets'))
        txPackets = float(flow_el.get('txPackets'))

        tx_duration = (parse_time_ns (flow_el.get('timeLastTxPacket')) - parse_time_ns(flow_el.get('timeFirstTxPacket')))*1e-9
        rx_duration = (parse_time_ns (flow_el.get('timeLastRxPacket')) - parse_time_ns(flow_el.get('timeFirstRxPacket')))*1e-9
        self.rx_duration = rx_duration
        self.probe_stats_unsorted = []
        if rxPackets:
            self.hopCount = float(flow_el.get('timesForwarded')) / rxPackets + 1
        else:
            self.hopCount = -1000
        if rxPackets:
            self.delayMean = float(flow_el.get('delaySum')[:-2]) / rxPackets * 1e-9
            self.packetSizeMean = float(flow_el.get('rxBytes')) / rxPackets
        else:
            self.delayMean = None
            self.packetSizeMean = None
        if rx_duration > 0:
            self.rxBitrate = float(flow_el.get('rxBytes'))*8 / rx_duration
        else:
            self.rxBitrate = None
        if tx_duration > 0:
            self.txBitrate = float(flow_el.get('txBytes'))*8 / tx_duration
        else:
            self.txBitrate = None
        lost = float(flow_el.get('lostPackets'))
        #print "rxBytes: %s; txPackets: %s; rxPackets: %s; lostPackets: %s" % (flow_el.get('rxBytes'), txPackets, rxPackets, lost)
        if rxPackets == 0:
            self.packetLossRatio = None
        else:
            self.packetLossRatio = (lost / (rxPackets + lost))

        interrupt_hist_elem = flow_el.find("flowInterruptionsHistogram")
        if interrupt_hist_elem is None:
            self.flowInterruptionsHistogram = None
        else:
            self.flowInterruptionsHistogram = Histogram(interrupt_hist_elem)

## ProbeFlowStats
class ProbeFlowStats(object):
    ## class variables
    ## @var probeId
    #  probe ID
    ## @var packets
    #  network packets
    ## @var bytes
    #  bytes
    ## @var delayFromFirstProbe
    #  delay from first probe
    ## @var __slots_
    #  class variable list
    __slots_ = ['probeId', 'packets', 'bytes', 'delayFromFirstProbe']

## Simulation
class Simulation(object):
    ## class variables
    ## @var flows
    #  list of flows
    def __init__(self, simulation_el):
        '''! The initializer.
        @param self The object pointer.
        @param simulation_el The element.
        '''
        self.flows = []
        FlowClassifier_el, = simulation_el.findall("Ipv4FlowClassifier")
        flow_map = {}
        for flow_el in simulation_el.findall("FlowStats/Flow"):
            flow = Flow(flow_el)
            flow_map[flow.flowId] = flow
            self.flows.append(flow)
        for flow_cls in FlowClassifier_el.findall("Flow"):
            flowId = int(flow_cls.get('flowId'))
            flow_map[flowId].fiveTuple = FiveTuple(flow_cls)

        for probe_elem in simulation_el.findall("FlowProbes/FlowProbe"):
            probeId = int(probe_elem.get('index'))
            for stats in probe_elem.findall("FlowStats"):
                flowId = int(stats.get('flowId'))
                s = ProbeFlowStats()
                s.packets = int(stats.get('packets'))
                s.bytes = float(stats.get('bytes'))
                s.probeId = probeId
                if s.packets > 0:
                    s.delayFromFirstProbe =  parse_time_ns(stats.get('delayFromFirstProbeSum')) / float(s.packets)
                else:
                    s.delayFromFirstProbe = 0
                flow_map[flowId].probe_stats_unsorted.append(s)


def main(argv):
    file_obj = open(argv[1])
    print("Reading XML file ", end=" ")
 
    sys.stdout.flush()        
    level = 0
    sim_list = []
    for event, elem in ElementTree.iterparse(file_obj, events=("start", "end")):
        if event == "start":
            level += 1
        if event == "end":
            level -= 1
            if level == 0 and elem.tag == 'FlowMonitor':
                sim = Simulation(elem)
                sim_list.append(sim)
                elem.clear() # won't need this any more
                sys.stdout.write(".")
                sys.stdout.flush()
    print(" done.")


    for sim in sim_list:
        for flow in sim.flows:
            t = flow.fiveTuple
            proto = {6: 'TCP', 17: 'UDP'} [t.protocol]
            print("FlowID: %i (%s %s/%s --> %s/%i)" % \
                (flow.flowId, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort))
            if flow.txBitrate is None:
                print("\tTX bitrate: None")
            else:
                print("\tTX bitrate: %.2f kbit/s" % (flow.txBitrate*1e-3,))
            if flow.rxBitrate is None:
                print("\tRX bitrate: None")
            else:
                print("\tRX bitrate: %.2f kbit/s" % (flow.rxBitrate*1e-3,))
            if flow.delayMean is None:
                print("\tMean Delay: None")
            else:
                print("\tMean Delay: %.2f ms" % (flow.delayMean*1e3,))
            if flow.packetLossRatio is None:
                print("\tPacket Loss Ratio: None")
            else:
                print("\tPacket Loss Ratio: %.2f %%" % (flow.packetLossRatio*100))


if __name__ == '__main__':
    main(sys.argv)

处理xml
在这里插入图片描述

如我用协议AODV的话 Port就是 654
在这里插入图片描述
还有一个例子,模拟业务流量的时候用的是端口9,这里 Port 9是服务器端口,客户端和服务器之间的区分在于 客户端是请求应用的发起者,然后服务器朝着客户端发送data(实际的业务payload)信息。(当然客户端也会向服务端发些信息这都没有问题)

运行脚本中通常的数据包UDP端口 9

数据业务端口配置注意用户socket配置的是9端口。

RoutingExperiment::RoutingExperiment ()
  : port (9),
  ····
}
····
Ptr<Socket>
RoutingExperiment::SetupPacketReceive (Ipv4Address addr, Ptr<Node> node)
{
  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
  Ptr<Socket> sink = Socket::CreateSocket (node, tid);
  InetSocketAddress local = InetSocketAddress (addr, port);
  sink->Bind (local);
  sink->SetRecvCallback (MakeCallback (&RoutingExperiment::ReceivePacket, this));

  return sink;
}

············
  Ipv4AddressHelper addressAdhoc;
  addressAdhoc.SetBase ("10.1.1.0", "255.255.255.0");
  Ipv4InterfaceContainer adhocInterfaces;
  adhocInterfaces = addressAdhoc.Assign (adhocDevices);

  OnOffHelper onoff1 ("ns3::UdpSocketFactory",Address ());
  onoff1.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1.0]"));
  onoff1.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0.0]"));

  for (int i = 0; i < nSinks; i++)
    {
      Ptr<Socket> sink = SetupPacketReceive (adhocInterfaces.GetAddress (i), adhocNodes.Get (i));

      AddressValue remoteAddress (InetSocketAddress (adhocInterfaces.GetAddress (i), port));
      onoff1.SetAttribute ("Remote", remoteAddress);

      Ptr<UniformRandomVariable> var = CreateObject<UniformRandomVariable> ();
      ApplicationContainer temp = onoff1.Install (adhocNodes.Get (i + nSinks));
      temp.Start (Seconds (var->GetValue (100.0,101.0)));
      temp.Stop (Seconds (TotalTime));
    }

路由协议控制开销分析 (方法1 .tr 文件分析)

用flowmonitor只能用于统计点到点的流,不能用于统计 一到多的包,因为其元组定义是需要目的ip的。进而可以知道,不能用于统计路由控制信息(路由开销)(因为路由控制信息,有广播信息 有单播信息 ,如 OLSR中的HELLO包、TC包都是广播包,是无法用 flowmonitor 统计出来的; AODV的RREQ是广播包也不能统计,RREP是单播包可以统计)

要想统计路由开销(路由协议发出的广播包 单播包等),需要对.tr文件进行分析

如这里所示:

aodv

ns3::WifiMacHeader (DATA 省略) ns3::LlcSnapHeader (省略) ns3::Ipv4Header (省略 length: 48 10.1.1.9 > 10.1.1.255) ns3::UdpHeader (length: 28 654 > 654) ns3::aodv::TypeHeader (RREP) ns3::aodv::RrepHeader (省略) ns3::WifiMacTrailer ()

ns3::WifiMacHeader (DATA 省略) ns3::LlcSnapHeader (省略) ns3::Ipv4Header (省略 length: 52 10.1.1.17 > 10.1.1.255) ns3::UdpHeader (length: 32 654 > 654) ns3::aodv::TypeHeader (RREQ) ns3::aodv::RreqHeader (省略) ns3::WifiMacTrailer ()

ns3::WifiMacHeader (DATA 省略) ns3::LlcSnapHeader (省略) ns3::Ipv4Header (省略 length: 40 10.1.1.39 > 10.1.1.18) ns3::UdpHeader (length: 20 654 > 654) ns3::aodv::TypeHeader (RERR) ns3::aodv::RerrHeader (省略) ns3::WifiMacTrailer ()

ns3::WifiMacHeader (DATA 省略) ns3::LlcSnapHeader (省略) ns3::Ipv4Header (省略 length: 92 10.1.1.20 > 10.1.1.10) ns3::UdpHeader (length: 72 49153 > 9) Payload (size=64) ns3::WifiMacTrailer ()

对于非广播的MAC包,如RREP,RREQ等, 以及 PayLoad包,MAC层也要传输ACK等控制包:

ns3::WifiMacHeader (CTL_ACK 省略) ns3::WifiMacTrailer ()

鉴于各层做各层的事情,在统计网络层路由协议开销的时候,MAC层发送的ACK根据情况一般不统计。 只统计网络层发送的控制包。

OLSR

对于OLSR路由协议来说,其控制包都是广播包,因此 flowmonitor 不能识别这些 olsr::MessageHeader。

ns3::WifiMacHeader (DATA 省略) ns3::LlcSnapHeader (省略) ns3::Ipv4Header (省略 length: 48 10.1.1.37 > 10.1.1.255) ns3::UdpHeader (length: 28 698 > 698) ns3::olsr::PacketHeader () ns3::olsr::MessageHeader () ns3::WifiMacTrailer ()

用tr文件识别路由协议的控制开销(AODV 654端口 OLSR 698 端口 DSDV 269端口)

根据上面的分析,处理tr文件,可以根据不同端口号区分所发送的信息是 data还是控制message,可以用python额外处理或者在仿真.cc文件中运行字符串处理的函数
1.读取.tr 文件的每一行,然后识别出 t 开头的。
2. 找到其中含有各协议端口号的包,或者含有 aodv::TypeHeader/ olsr::PacketHeader/ dsdv::DsdvHeader 的包。
3. 计数即可,即为发出的网络层控制包的数量。 精细一点,也可以用字符串处理,取出其中包的大小.

特别的对于DSR等其他特殊路由协议

对于不熟悉的路由协议,建议都看一下tr文件,看看这种路由协议是从哪一层发出来的。

ns3::WifiMacHeader (DATA 省略) ns3::LlcSnapHeader (省略) ns3::Ipv4Header (省略 length: 44 10.1.1.40 > 10.1.1.255) ns3::DsrRoutingHeader ( nextHeader: 17 messageType: 1 sourceId: 13 destinationId: 255 length: 16) ns3::WifiMacTrailer ()

ns3::WifiMacHeader (DATA 省略) ns3::LlcSnapHeader (省略) ns3::Ipv4Header (省略 length: 124 10.1.1.14 > 10.1.1.42) ns3::DsrRoutingHeader ( nextHeader: 17 messageType: 2 sourceId: 13 destinationId: 3 length: 24) ns3::UdpHeader (length: 72 49153 > 9) Payload (size=64) ns3::WifiMacTrailer ()

可以发现其包并不是通过UDP包发送的,而是直接通过IP包发送的,DSR是一种 IP层和UDP之间作用的。在发送数据包时,也是把UDP的包装在了Dsr包中。

在统计的时候,DsrRoutingHeader后面含有UdpHeader Payload 的即为数据包,不含的则为控制包。

使用本博文内容和参考代码(代码1 和 代码2)的出版物请标注本博文链接的引用

(在仿真.cc文件中添加)

代码1 如下

代码1.1 函数分析.tr文件分析

// huph huph197@163.com
// 统计tr文件 声明一个函数
void SendCount(std::string _path, uint64_t *SendNumArray)
{
std::string str;
std::string begin;
SendNumArray[0]=0;
SendNumArray[1]=0;
//uint64_t sTotal=0;

std:: ifstream in;
in.open(_path.c_str());
while(!in.eof())
 {
	std::getline(in,str);
        begin=str.substr(0,1);
        if(begin=="t")
         {
          if(str.find("Ipv4Header")) //不看mac层以下
              {   
                 //cout<<begin<<endl;
                 if(str.find("Payload")<100000)// 找到了数据包
                 //cout <<"发送和转发的数据包" <<endl;
                 SendNumArray[0]++;
                 if(str.find("aodv")||str.find("olsr")||str.find("dsdv")||str.find("dsr"))
                  //cout <<"发送和转发的控制包(控制包可以当做控制开销的衡量)" <<endl;
                 SendNumArray[1]++;
                 /****************/
				//找长度
              }
                 /***************/
         }
}
in.close();
}

代码1.2 调用函数分析.tr,获取统计值

在统计部分: totalRx 是 flowmonitor 统计的收到的(源节点到目的节点的)数据包个数。

// huph huph197@163.com
  uint64_t SendArray[2];//Array[0]发送和转发的数据包;Array[1]发送和转发的控制包
  SendCount("你的tr文件名.tr",SendArray);
  double normalcost = (double) SendArray[1]/( SendArray[1] +totalRx);
  NS_LOG_UNCOND("normalcost:" << normalcost);

NS3中路由协议控制开销分析 (方法二: 用wireshark 对路由协议的控制开销进行分析)

在代码中添加 pcap跟踪组件

  // wifiPhy.EnablePcap("mannet-first",adhocDevices,false);
  // wifiPhy.EnablePcapAll("mannet-second",false);
  // wifiPhy.EnablePcap("mannet-third",adhocDevices,true);
  wifiPhy.EnablePcapAll("mannet-forth",true);
// void WifiPhyHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename)

输出文件名为:
mannet-forth-0-0.pcap mannet-forth-1-0.pcap mannet-forth-2-0.pcap mannet-forth-3-0.pcap mannet-forth-4-0.pcap mannet-forth-5-0.pcap mannet-forth-6-0.pcap mannet-forth-7-0.pcap mannet-forth-8-0.pcap mannet-forth-9-0.pcap mannet-forth-10-0.pcap mannet-forth-11-0.pcap mannet-forth-12-0.pcap mannet-forth-13-0.pcap mannet-forth-14-0.pcap mannet-forth-15-0.pcap mannet-forth-16-0.pcap mannet-forth-17-0.pcap mannet-forth-18-0.pcap mannet-forth-19-0.pcap mannet-forth-20-0.pcap mannet-forth-21-0.pcap mannet-forth-22-0.pcap mannet-forth-23-0.pcap mannet-forth-24-0.pcap mannet-forth-25-0.pcap mannet-forth-26-0.pcap mannet-forth-27-0.pcap mannet-forth-28-0.pcap mannet-forth-29-0.pcap mannet-forth-30-0.pcap mannet-forth-31-0.pcap mannet-forth-32-0.pcap mannet-forth-33-0.pcap mannet-forth-34-0.pcap mannet-forth-35-0.pcap mannet-forth-36-0.pcap mannet-forth-37-0.pcap mannet-forth-38-0.pcap mannet-forth-39-0.pcap mannet-forth-40-0.pcap mannet-forth-41-0.pcap mannet-forth-42-0.pcap mannet-forth-43-0.pcap mannet-forth-44-0.pcap mannet-forth-45-0.pcap mannet-forth-46-0.pcap mannet-forth-47-0.pcap mannet-forth-48-0.pcap mannet-forth-49-0.pcap

跟踪了50个节点,设备0上的发送行为

统计全部的pcap文件,需要对其进行合并,把这些文件放到一个文件夹中,比如pcaptemp下。
建立一个bash脚本,赋予运行权限后运行。

代码2 合并pcap文件的脚本

# huph huph197@163.com
path1="/home/hph/ns3.32/ns-3.32/pcaptemp" 
cd $path1
current_path=$(pwd)  
echo "当前路径是:$current_path"
for i in $(seq 0 1 49)
do      
printf mannet-forth-$i-0.pcap 
printf " "
# mergecap -w Merge.pcap Merge.pcap mannet-forth-0-0.pcap mannet-forth-1-0.pcap
done

mergecap -w Merge.pcap mannet-forth-0-0.pcap mannet-forth-1-0.pcap mannet-forth-2-0.pcap mannet-forth-3-0.pcap mannet-forth-4-0.pcap mannet-forth-5-0.pcap mannet-forth-6-0.pcap mannet-forth-7-0.pcap mannet-forth-8-0.pcap mannet-forth-9-0.pcap mannet-forth-10-0.pcap mannet-forth-11-0.pcap mannet-forth-12-0.pcap mannet-forth-13-0.pcap mannet-forth-14-0.pcap mannet-forth-15-0.pcap mannet-forth-16-0.pcap mannet-forth-17-0.pcap mannet-forth-18-0.pcap mannet-forth-19-0.pcap mannet-forth-20-0.pcap mannet-forth-21-0.pcap mannet-forth-22-0.pcap mannet-forth-23-0.pcap mannet-forth-24-0.pcap mannet-forth-25-0.pcap mannet-forth-26-0.pcap mannet-forth-27-0.pcap mannet-forth-28-0.pcap mannet-forth-29-0.pcap mannet-forth-30-0.pcap mannet-forth-31-0.pcap mannet-forth-32-0.pcap mannet-forth-33-0.pcap mannet-forth-34-0.pcap mannet-forth-35-0.pcap mannet-forth-36-0.pcap mannet-forth-37-0.pcap mannet-forth-38-0.pcap mannet-forth-39-0.pcap mannet-forth-40-0.pcap mannet-forth-41-0.pcap mannet-forth-42-0.pcap mannet-forth-43-0.pcap mannet-forth-44-0.pcap mannet-forth-45-0.pcap mannet-forth-46-0.pcap mannet-forth-47-0.pcap mannet-forth-48-0.pcap mannet-forth-49-0.pcap 

其中 mergecap -w Merge.pcap 文件1.pcap 文件1.pcap 文件2.pcap …是合并命令,-w用于按照时间顺序合并信息

合并完以后,用 wireshark打开 Merge.pcap 在统计-协议分级 中可以看出:

几种协议的包情况:

olsr

在这里插入图片描述

aodv

在这里插入图片描述

dsdv

在这里插入图片描述

dsr

在这里插入图片描述

从中获取各种协议在IP的包情况(如 分组百分比)

协议用户数据包用户控制包地址处理
olsr16.173.02.3
aodv14.952.35.5
dsdv16.477.80.7
dsr0.469.07.2

其他的有关利用wireshark的分析可以自行学习

参考

[FlowMonitor] G. Carneiro, P. Fortuna, and M. Ricardo. 2009. FlowMonitor: a network monitoring framework for the network simulator 3 (NS-3). In Proceedings of the Fourth International ICST Conference on Performance Evaluation Methodologies and Tools (VALUETOOLS '09).
为什么 FlowMonitor 不收集 ns3 中 dsr.cc 的数据

https://stackoverflow.com/questions/51800123/why-does-flowmonitor-not-collect-data-for-dsr-cc-in-ns3

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值