diff --git a/doc/howtos/howtos-application.h b/doc/howtos/howtos-application.h new file mode 100644 index 000000000..33ba848c3 --- /dev/null +++ b/doc/howtos/howtos-application.h @@ -0,0 +1,203 @@ +/*! + \page application How to create a traffic generator ? + \anchor howtos-application + + Question: How do I create a new traffic generator ? + + Answer: It is possible to instanciate \ref ns3::Packet "Packet" + objects, schedule events, and call functions from any piece of code + in ns-3 so, technically, there is no single answer to the question of + how we can write a new traffic generator. However, the + \ref ns3::Socket "Socket" API was really designed to be the single + point of entry for traffic generators or traffic analysers and the + \ref ns3::Application "Application" class was designed to hold + together any number of sockets. + + Implementing a new traffic generator thus boils down to: +- implementing a new subclass of the \ref ns3::Application "Application" + base class +- instanciate one or many sockets within that application +- start scheduling events when \ref ns3::Application::StartApplication "StartApplication" + is called +- stop scheduling events when \ref ns3::Application::StopApplication "StopApplication" + is called +- create packets and send them over one or many sockets in each event + +The following "random" generator generates packets separated by a random +delay and with a random size. + +\code +class RandomGenerator : public Application +{ +public: + RandomGenerator (); + void SetDelay (RandomVariable delay); + void SetSize (RandomVariable size); + void SetRemote (std::string socketType, + Address remote); +private: + virtual void StartApplication (void); + virtual void StopApplication (void); + void DoGenerate (void); + + RandomVariable m_delay; + RandomVariable m_size; + Ptr m_socket; +}; +\endcode + +The socket is created in the SetRemote method: +\code +void +RandomGenerator::SetRemote (std::string socketType, + Address remote) +{ + TypeId tid = TypeId::LookupByName (socketType); + m_socket = Socket::CreateSocket (GetNode (), tid); + m_socket->Bind (); + m_socket->ShutdownRecv (); + m_socket->Connect (remote); +} +\endcode +While the the crux of the logic is located in the DoGenerate method +which is called from within StartApplication: +\code +void +RandomGenerator::DoGenerate (void) +{ + m_next = Simulator::Schedule (Seconds (m_delay.GetValue ()), + &RandomGenerator::DoGenerate, this); + Ptr p = Create (m_size.GetIntValue ()); + m_socket->Send (p); +} +\endcode + +To make that application more integrated in ns-3, it needs an associated +helper class: +\code +class RandomAppHelper +{ +public: + RandomAppHelper (std::string protocol, Address remote); + void SetPacketSize (RandomVariable packetSize); + void SetDelay (RandomVariable delay); + ApplicationContainer Install (NodeContainer nodes); +private: + std::string m_protocol; + Address m_remote; + RandomVariable m_packetSize; + RandomVariable m_delay; +}; +\endcode + +which could be trivially implemented as: +\code +ApplicationContainer +RandomAppHelper::Install (NodeContainer nodes) +{ + ApplicationContainer applications; + for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i) + { + Ptr app = CreateObject (); + app->SetSize (m_packetSize); + app->SetDelay (m_delay); + app->SetRemote (m_protocol, m_remote); + (*i)->AddApplication (app); + applications.Add (app); + } + return applications; +} +\endcode + +Despite being functional, this API is not very consistant with the style of +the other helper classes, all of which allow you to control the parameters +of the underlying class through attributes and not explicit setters. The +following API thus replaces the pair SetPacketSize/SetDelay with a single +method SetAttribute: +\code +class RandomAppHelper +{ +public: + RandomAppHelper (std::string protocol, Address remote); + void SetAttribute (std::string name, const AttributeValue &value); + ApplicationContainer Install (NodeContainer c); +private: + std::string m_protocol; + Address m_remote; + ObjectFactory m_factory; +}; +\endcode + +And which can be used as follows: +\code +RandomAppHelper app = RandomAppHelper ("ns3::TcpSocketFactory", + InetSocketAddress (Ipv4Address ("192.168.1.10"), 10)); +app.SetAttribute ("Delay", StringValue ("Constant:2.5")); +app.SetAttribute ("Size", StringValue ("Constant:2100")); +app.Install (nodes); +\endcode + +The implementation, in this case, is not necessarily longer but its +simplicity hides a lot of behind-the-scenes complexity: + +\code +void +RandomAppHelper::SetAttribute (std::string name, const AttributeValue &value) +{ + m_factory.Set (name, value); +} +ApplicationContainer +RandomAppHelper::Install (NodeContainer nodes) +{ + ApplicationContainer applications; + for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i) + { + Ptr app = m_factory.Create (); + app->SetRemote (m_socketType, m_remote); + (*i)->AddApplication (app); + applications.Add (app); + } + return applications; +} +\endcode + +The key difference between this implementation and the previous one +is that this helper does not handle explicitely the attributes +delay and packet size. Instead, it stores them in an +\ref ns3::ObjectFactory "ObjectFactory" object. This, of course, +does not work magically, and requires extra support from the +underlying RandomGenerator class. Specifically, it requires +that the underlying RandomGenerator defines its attributes +in its \ref ns3::TypeId "TypeId" in a new public static method: + +\code +class RandomGenerator +{ +public: + static TypeId GetTypeId (void); +}; +\endcode + +The corresponding implementation is shown below: + +\code +TypeId +RandomGenerator::GetTypeId (void) +{ + static TypeId tid = TypeId ("RandomGenerator") + .SetParent () + .AddConstructor () + .AddAttribute ("Delay", "The delay between two packets (s)", + RandomVariableValue (ConstantVariable (1.0)), + MakeRandomVariableAccessor (&RandomGenerator::m_delay), + MakeRandomVariableChecker ()) + .AddAttribute ("PacketSize", "The size of each packet (bytes)", + RandomVariableValue (ConstantVariable (2000)), + MakeRandomVariableAccessor (&RandomGenerator::m_size), + MakeRandomVariableChecker ()) + ; + return tid; +} +\endcode + +*/ diff --git a/doc/howtos/howtos.h b/doc/howtos/howtos.h index 2e84cd8e6..199b0d1b9 100644 --- a/doc/howtos/howtos.h +++ b/doc/howtos/howtos.h @@ -11,9 +11,10 @@ for ns-3. This complements the following wiki pages: Please consider contributing tips to either the wiki (yourself) or by submitting a patch to this maintained documentation. -- \subpage net-device - \subpage callbacks - \subpage packet-header-trailer +- \subpage net-device +- \subpage application */