add sixth tutorial example for mid-level tracing helpers
authorCraig Dowell <craigdo@ee.washington.edu>
Mon, 25 Jan 2010 16:09:07 -0800
changeset 6020 f8212529e82a
parent 6019 adc48a1def77
child 6021 fddc1ed290f8
add sixth tutorial example for mid-level tracing helpers
doc/tutorial/tracing.texi
examples/tutorial/sixth.cc
examples/tutorial/wscript
--- a/doc/tutorial/tracing.texi	Mon Jan 25 15:28:43 2010 -0800
+++ b/doc/tutorial/tracing.texi	Mon Jan 25 16:09:07 2010 -0800
@@ -17,6 +17,8 @@
 @menu
 * Background::
 * Overview::
+* A Real Example::
+* Using Mid-Level Helpers::
 @end menu
 
 @c ============================================================================
@@ -1901,4 +1903,30 @@
 @sp 1
 @center @image{figures/cwnd,,,,png}
 
+@c ============================================================================
+@c Using Mid-Level Helpers
+@c ============================================================================
+@node Using Mid-Level Helpers
+@section Using Mid-Level Helpers
 
+In the previous section, we showed how to hook a trace source and get hopefully
+interesting information out of a simulation.  Perhaps you will recall that we 
+called logging to the standard output using @code{std::cout} a ``Blunt Instrument'' 
+much earlier in this chapter.  We also wrote about how it was a problem having
+to parse the log output in order to isolate interesting information.  It may 
+have occurred to you that we just spent a lot of time implementing an example
+that exhibits all of the problems we purport to fix with the @code{ns-3} tracing
+system!  You would be correct.  But, bear with us.  We're not done yet.
+
+One of the most important things we want to do is to is to have the ability to 
+easily control the amount of output coming out of the simulation; and we also 
+want to save those data to a file so we can refer back to it later.  We can use
+the mid-level trace helpers provided in @code{ns-3} to do just that and complete
+the picture.
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tutorial/sixth.cc	Mon Jan 25 16:09:07 2010 -0800
@@ -0,0 +1,231 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <fstream>
+#include "ns3/core-module.h"
+#include "ns3/common-module.h"
+#include "ns3/simulator-module.h"
+#include "ns3/node-module.h"
+#include "ns3/helper-module.h"
+#include "ns3/ascii-trace-helper.h"
+#include "ns3/pcap-helper.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SixthScriptExample");
+
+// ===========================================================================
+//
+//         node 0                 node 1
+//   +----------------+    +----------------+
+//   |    ns-3 TCP    |    |    ns-3 TCP    |
+//   +----------------+    +----------------+
+//   |    10.1.1.1    |    |    10.1.1.2    |
+//   +----------------+    +----------------+
+//   | point-to-point |    | point-to-point |
+//   +----------------+    +----------------+
+//           |                     |
+//           +---------------------+
+//                5 Mbps, 2 ms
+//
+//
+// We want to look at changes in the ns-3 TCP congestion window.  We need
+// to crank up a flow and hook the CongestionWindow attribute on the socket
+// of the sender.  Normally one would use an on-off application to generate a
+// flow, but this has a couple of problems.  First, the socket of the on-off 
+// application is not created until Application Start time, so we wouldn't be 
+// able to hook the socket (now) at configuration time.  Second, even if we 
+// could arrange a call after start time, the socket is not public so we 
+// couldn't get at it.
+//
+// So, we can cook up a simple version of the on-off application that does what
+// we want.  On the plus side we don't need all of the complexity of the on-off
+// application.  On the minus side, we don't have a helper, so we have to get
+// a little more involved in the details, but this is trivial.
+//
+// So first, we create a socket and do the trace connect on it; then we pass 
+// this socket into the constructor of our simple application which we then 
+// install in the source node.
+// ===========================================================================
+//
+class MyApp : public Application 
+{
+public:
+
+  MyApp ();
+  virtual ~MyApp();
+
+  void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
+
+private:
+  virtual void StartApplication (void);  
+  virtual void StopApplication (void);
+
+  void ScheduleTx (void);
+  void SendPacket (void);
+
+  Ptr<Socket>     m_socket;
+  Address         m_peer;
+  uint32_t        m_packetSize;
+  uint32_t        m_nPackets;
+  DataRate        m_dataRate;
+  EventId         m_sendEvent;
+  bool            m_running;
+  uint32_t        m_packetsSent;
+};
+
+MyApp::MyApp ()
+  : m_socket (0), 
+    m_peer (), 
+    m_packetSize (0), 
+    m_nPackets (0), 
+    m_dataRate (0), 
+    m_sendEvent (), 
+    m_running (false), 
+    m_packetsSent (0)
+{
+}
+
+MyApp::~MyApp()
+{
+  m_socket = 0;
+}
+
+void
+MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
+{
+  m_socket = socket;
+  m_peer = address;
+  m_packetSize = packetSize;
+  m_nPackets = nPackets;
+  m_dataRate = dataRate;
+}
+
+void
+MyApp::StartApplication (void)
+{
+  m_running = true;
+  m_packetsSent = 0;
+  m_socket->Bind ();
+  m_socket->Connect (m_peer);
+  SendPacket ();
+}
+
+void 
+MyApp::StopApplication (void)
+{
+  m_running = false;
+
+  if (m_sendEvent.IsRunning ())
+    {
+      Simulator::Cancel (m_sendEvent);
+    }
+
+  if (m_socket)
+    {
+      m_socket->Close ();
+    }
+}
+
+void 
+MyApp::SendPacket (void)
+{
+  Ptr<Packet> packet = Create<Packet> (m_packetSize);
+  m_socket->Send (packet);
+
+  if (++m_packetsSent < m_nPackets)
+    {
+      ScheduleTx ();
+    }
+}
+
+void 
+MyApp::ScheduleTx (void)
+{
+  if (m_running)
+    {
+      Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
+      m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
+    }
+}
+
+static void
+CwndChange (Ptr<OutputStreamObject> stream, uint32_t oldCwnd, uint32_t newCwnd)
+{
+  *stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
+}
+
+static void
+RxDrop (Ptr<PcapFileObject> file, Ptr<const Packet> p)
+{
+  file->Write(Simulator::Now(), p);
+}
+
+int 
+main (int argc, char *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 = CreateObjectWithAttributes<RateErrorModel> (
+    "RanVar", RandomVariableValue (UniformVariable (0., 1.)),
+    "ErrorRate", DoubleValue (0.00001));
+  devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
+
+  InternetStackHelper stack;
+  stack.Install (nodes);
+
+  Ipv4AddressHelper address;
+  address.SetBase ("10.1.1.0", "255.255.255.252");
+  Ipv4InterfaceContainer interfaces = address.Assign (devices);
+
+  uint16_t sinkPort = 8080;
+  Address sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
+  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
+  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 ());
+
+  AsciiTraceHelper asciiTraceHelper;
+  Ptr<OutputStreamObject> stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd");
+  ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
+
+  Ptr<MyApp> app = CreateObject<MyApp> ();
+  app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
+  nodes.Get (0)->AddApplication (app);
+  app->SetStartTime (Seconds (1.));
+  app->SetStopTime (Seconds (20.));
+
+  PcapHelper pcapHelper;
+  Ptr<PcapFileObject> file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_EN10MB);
+  devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file));
+
+  Simulator::Stop (Seconds(20));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
+
--- a/examples/tutorial/wscript	Mon Jan 25 15:28:43 2010 -0800
+++ b/examples/tutorial/wscript	Mon Jan 25 16:09:07 2010 -0800
@@ -18,3 +18,6 @@
 
     obj = bld.create_ns3_program('fifth', ['core', 'simulator', 'point-to-point', 'internet-stack'])
     obj.source = 'fifth.cc'
+
+    obj = bld.create_ns3_program('sixth', ['core', 'simulator', 'point-to-point', 'internet-stack'])
+    obj.source = 'sixth.cc'