개인 공부

NS-3 독학 - 完. Seventh.cc

Beige00 2024. 1. 15. 15:46
/**
 * Congestion window change callback
 *
 * \param stream The output stream file.
 * \param oldCwnd Old congestion window.
 * \param newCwnd New congestion window.
 */
static void
CwndChange(Ptr<OutputStreamWrapper> stream, uint32_t oldCwnd, uint32_t newCwnd)
{
    NS_LOG_UNCOND(Simulator::Now().GetSeconds() << "\t" << newCwnd);
    *stream->GetStream() << Simulator::Now().GetSeconds() << "\t" << oldCwnd << "\t" << newCwnd
                         << std::endl;
}

/**
 * Rx drop callback
 *
 * \param file The output PCAP file.
 * \param p The dropped packet.
 */
static void
RxDrop(Ptr<PcapFileWrapper> file, Ptr<const Packet> p)
{
    NS_LOG_UNCOND("RxDrop at " << Simulator::Now().GetSeconds());
    file->Write(Simulator::Now(), p);
}

int
main(int argc, char* argv[])
{
    bool useV6 = false;

    CommandLine cmd(__FILE__);
    cmd.AddValue("useIpv6", "Use Ipv6", useV6);
    cmd.Parse(argc, argv);

    NodeContainer nodes;
    nodes.Create(2);

    PointToPointHelper pointToPoint;
    pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
    pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));

    NetDeviceContainer devices;
    devices = pointToPoint.Install(nodes);

    Ptr<RateErrorModel> em = CreateObject<RateErrorModel>();
    em->SetAttribute("ErrorRate", DoubleValue(0.00001));
    devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(em));

    InternetStackHelper stack;
    stack.Install(nodes);

    uint16_t sinkPort = 8080;
    Address sinkAddress;
    Address anyAddress;
    std::string probeType;
    std::string tracePath;
    if (!useV6)
    {
        Ipv4AddressHelper address;
        address.SetBase("10.1.1.0", "255.255.255.0");
        Ipv4InterfaceContainer interfaces = address.Assign(devices);
        sinkAddress = InetSocketAddress(interfaces.GetAddress(1), sinkPort);
        anyAddress = InetSocketAddress(Ipv4Address::GetAny(), sinkPort);
        probeType = "ns3::Ipv4PacketProbe";
        tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
    }
    else
    {
        Ipv6AddressHelper address;
        address.SetBase("2001:0000:f00d:cafe::", Ipv6Prefix(64));
        Ipv6InterfaceContainer interfaces = address.Assign(devices);
        sinkAddress = Inet6SocketAddress(interfaces.GetAddress(1, 1), sinkPort);
        anyAddress = Inet6SocketAddress(Ipv6Address::GetAny(), sinkPort);
        probeType = "ns3::Ipv6PacketProbe";
        tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
    }

    PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", anyAddress);
    ApplicationContainer sinkApps = packetSinkHelper.Install(nodes.Get(1));
    sinkApps.Start(Seconds(0.));
    sinkApps.Stop(Seconds(20.));

    Ptr<Socket> ns3TcpSocket = Socket::CreateSocket(nodes.Get(0), TcpSocketFactory::GetTypeId());

    Ptr<TutorialApp> app = CreateObject<TutorialApp>();
    app->Setup(ns3TcpSocket, sinkAddress, 1040, 1000, DataRate("1Mbps"));
    nodes.Get(0)->AddApplication(app);
    app->SetStartTime(Seconds(1.));
    app->SetStopTime(Seconds(20.));

    AsciiTraceHelper asciiTraceHelper;
    Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream("seventh.cwnd");
    ns3TcpSocket->TraceConnectWithoutContext("CongestionWindow",
                                             MakeBoundCallback(&CwndChange, stream));

    PcapHelper pcapHelper;
    Ptr<PcapFileWrapper> file =
        pcapHelper.CreateFile("seventh.pcap", std::ios::out, PcapHelper::DLT_PPP);
    devices.Get(1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback(&RxDrop, file));

    // Use GnuplotHelper to plot the packet byte count over time
    GnuplotHelper plotHelper;

    // Configure the plot.  The first argument is the file name prefix
    // for the output files generated.  The second, third, and fourth
    // arguments are, respectively, the plot title, x-axis, and y-axis labels
    plotHelper.ConfigurePlot("seventh-packet-byte-count",
                             "Packet Byte Count vs. Time",
                             "Time (Seconds)",
                             "Packet Byte Count");

    // Specify the probe type, trace source path (in configuration namespace), and
    // probe output trace source ("OutputBytes") to plot.  The fourth argument
    // specifies the name of the data series label on the plot.  The last
    // argument formats the plot by specifying where the key should be placed.
    plotHelper.PlotProbe(probeType,
                         tracePath,
                         "OutputBytes",
                         "Packet Byte Count",
                         GnuplotAggregator::KEY_BELOW);

    // Use FileHelper to write out the packet byte count over time
    FileHelper fileHelper;

    // Configure the file to be written, and the formatting of output data.
    fileHelper.ConfigureFile("seventh-packet-byte-count", FileAggregator::FORMATTED);

    // Set the labels for this formatted output file.
    fileHelper.Set2dFormat("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");

    // Specify the probe type, trace source path (in configuration namespace), and
    // probe output trace source ("OutputBytes") to write.
    fileHelper.WriteProbe(probeType, tracePath, "OutputBytes");

    Simulator::Stop(Seconds(20));
    Simulator::Run();
    Simulator::Destroy();

    return 0;
}

코드 전문이다.

Seventh.cc 역시 fifth.cc와 유사한 형태이다.

같은 네트워크 토폴로지를 가정하고 있으며, 차이점은 sixth에서는 데이터 파일을 만들었다면, seventh에서는 만든 데이터 파일을 Gnuplot을 이용해 그래프로 나타내는 방법을 알려준다.

(fifth, sixth.cc와 같은 부분은 설명 x)

 

1.  bool useV6 = false;

이름을 보고, 소스 코드를 보면 알 수 있듯이, 시뮬레이션에 IpV4를 쓸 지, V6를 쓸 지를 결정하는 부분이다.

 

2. uint16_t sinkPort = 8080;
    Address sinkAddress;
    Address anyAddress;
    std::string probeType;
    std::string tracePath;
    if (!useV6)
    {
        Ipv4AddressHelper address;
        address.SetBase("10.1.1.0", "255.255.255.0");
        Ipv4InterfaceContainer interfaces = address.Assign(devices);
        sinkAddress = InetSocketAddress(interfaces.GetAddress(1), sinkPort);
        anyAddress = InetSocketAddress(Ipv4Address::GetAny(), sinkPort);
        probeType = "ns3::Ipv4PacketProbe";
        tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
    }
    else
    {
        Ipv6AddressHelper address;
        address.SetBase("2001:0000:f00d:cafe::", Ipv6Prefix(64));
        Ipv6InterfaceContainer interfaces = address.Assign(devices);
        sinkAddress = Inet6SocketAddress(interfaces.GetAddress(1, 1), sinkPort);
        anyAddress = Inet6SocketAddress(Ipv6Address::GetAny(), sinkPort);
        probeType = "ns3::Ipv6PacketProbe";
        tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
    } :

IpV4인지, IpV6인지에 따라 주소와 데이터를 설정해주는 부분이다.

여기서 probeType은 GnuPlotHelper를 통해 그래프를 그릴 때 사용한다.

 

3. GnuplotHelper plotHelper;

    plotHelper.ConfigurePlot("seventh-packet-byte-count",
                             "Packet Byte Count vs. Time",
                             "Time (Seconds)",
                             "Packet Byte Count");

    plotHelper.PlotProbe(probeType,
                         tracePath,
                         "OutputBytes",
                         "Packet Byte Count",
                         GnuplotAggregator::KEY_BELOW);

    FileHelper fileHelper;

    fileHelper.ConfigureFile("seventh-packet-byte-count", FileAggregator::FORMATTED);

    fileHelper.Set2dFormat("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");

    fileHelper.WriteProbe(probeType, tracePath, "OutputBytes"); :

GnuplotHelper를 통해 그래프를 그리는 부분이다.

ConfigurePlot( filename, plot title, x-axis name, y-axis name );

이므로, 완성된 그래프의 파일명은 "seventh-packe-byte-count"일 것이며, Graph의 이름은 Packet Byte~

x 축의 label은 Time(sec), y 축의 label은 PBC 라고 써있을 것이다.

 

이 후,  PlotProbe를 통해 그래프를 그린다.

Tracing value name은 probeType(ns3::Ipv4PacketProbe),

tracePath는 /NodeList/*/$ns3::Ipv4L3Protocol/Tx 이다. (Documentation 참고)

"OutputBytes"는 y에 작성할 데이터의 이름을 나타내며, Output

Bytes가 Packet Byte Count가 될 것이다.

GnuplotAggregator::KEY_BELOW를 통해 legend를 그래프 아래에 표시시킨다.

 

그래프를 전부 그렸으면 File에 저장을 시켜야한다.

따라서 seventh-packet-byte-count라는 파일을 만들고, Formatting된 형식으로 저장할 것을 선언한다.

이 후 형식을  "Time (Seconds) = %.3e\tPacket Byte Count = %.0f" 로 정해준 뒤, WirteProbe를 통해 

probeType, tracePath로 지정된 파일에서 OutputBytes를 파일에 추가시킨다.

 


* 실행 결과

생성된 파일 seventh-packet-byte-count.sh 에게 권한을 주고 실행하면 다음과 같은 그래프가 출력된다.

(gnuplot은 당연히 설치되어있어야한다.)

더보기

=> 만약 png 파일을 gnuplot이 인식하지 못한다면, https://github.com/libgd/libgd/releases 에서 최신버전 libgd tar.gz를 받아 압축해제, ./configure, make, sudo make install 을 통해 설치 후, gnuplot을 재설치하자.

그 후 gnuplot을 실행시켜 set terminal을 해서 png가 설치되었는지를 확인하자.

 

결과 파일.