Visualizing NS3 Simulations: A Step-by-Step Guide with NetAnim

In this post, we'll walk through a practical example of how to visualize a TCP star-server topology using NS3 and NetAnim. We'll set up a network with one central server and multiple clients, run the simulation, and then visualize it.
The Scenario: TCP Star Server
We'll use an example script that creates a star network topology. In this setup, several client nodes connect to a single central server node. The clients will send TCP traffic to the server.
The Simulation Code
Here is the complete C++ code for our tcp-star-server.cc
simulation. It defines the network topology, installs the necessary protocols, sets up the applications, and most importantly, includes the logic to generate the animation file.
C++
/*
* SPDX-License-Identifier: GPL-2.0-only
*/
// Default Network topology, 9 nodes in a star
/*
n2 n3 n4
\ | /
\|/
n1---n0---n5
/| \
/ | \
n8 n7 n6
*/
// - CBR Traffic goes from the star "arms" to the "hub"
// - Tracing of queues and packet receptions to file
// "tcp-star-server.tr"
// - pcap traces also generated in the following files
// "tcp-star-server-$n-$i.pcap" where n and i represent node and interface
// numbers respectively
// Usage examples for things you might want to tweak:
// ./ns3 run "tcp-star-server"
// ./ns3 run "tcp-star-server --nNodes=25"
// ./ns3 run "tcp-star-server --ns3::OnOffApplication::DataRate=10000"
// ./ns3 run "tcp-star-server --ns3::OnOffApplication::PacketSize=500"
// See the ns-3 tutorial for more info on the command line:
// https://www.nsnam.org/docs/tutorial/html/index.html
#include "ns3/applications-module.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/ipv4-global-routing-helper.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/netanim-module.h"
#include "ns3/mobility-module.h"
#include <cassert>
#include <fstream>
#include <iostream>
#include <string>
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("TcpServer");
int
main(int argc, char* argv[])
{
// Users may find it convenient to turn on explicit debugging
// for selected modules; the below lines suggest how to do this
// LogComponentEnable ("TcpServer", LOG_LEVEL_INFO);
// LogComponentEnable ("TcpL4Protocol", LOG_LEVEL_ALL);
// LogComponentEnable ("TcpSocketImpl", LOG_LEVEL_ALL);
// LogComponentEnable ("PacketSink", LOG_LEVEL_ALL);
// Set up some default values for the simulation.
Config::SetDefault("ns3::OnOffApplication::PacketSize", UintegerValue(250));
Config::SetDefault("ns3::OnOffApplication::DataRate", StringValue("5kb/s"));
uint32_t N = 9; // number of nodes in the star
// Allow the user to override any of the defaults and the above
// Config::SetDefault()s at run-time, via command-line arguments
CommandLine cmd(__FILE__);
cmd.AddValue("nNodes", "Number of nodes to place in the star", N);
cmd.Parse(argc, argv);
// Here, we will create N nodes in a star.
NS_LOG_INFO("Create nodes.");
NodeContainer serverNode;
NodeContainer clientNodes;
serverNode.Create(1);
clientNodes.Create(N - 1);
NodeContainer allNodes = NodeContainer(serverNode, clientNodes);
// Install network stacks on the nodes
InternetStackHelper internet;
internet.Install(allNodes);
// Set constant positions for all nodes
MobilityHelper mobility;
mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
mobility.Install(allNodes);
// Collect an adjacency list of nodes for the p2p topology
std::vector<NodeContainer> nodeAdjacencyList(N - 1);
for (uint32_t i = 0; i < nodeAdjacencyList.size(); ++i)
{
nodeAdjacencyList[i] = NodeContainer(serverNode, clientNodes.Get(i));
}
// We create the channels first without any IP addressing information
NS_LOG_INFO("Create channels.");
PointToPointHelper p2p;
p2p.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
p2p.SetChannelAttribute("Delay", StringValue("2ms"));
std::vector<NetDeviceContainer> deviceAdjacencyList(N - 1);
for (uint32_t i = 0; i < deviceAdjacencyList.size(); ++i)
{
deviceAdjacencyList[i] = p2p.Install(nodeAdjacencyList[i]);
}
// Later, we add IP addresses.
NS_LOG_INFO("Assign IP Addresses.");
Ipv4AddressHelper ipv4;
std::vector<Ipv4InterfaceContainer> interfaceAdjacencyList(N - 1);
for (uint32_t i = 0; i < interfaceAdjacencyList.size(); ++i)
{
std::ostringstream subnet;
subnet << "10.1." << i + 1 << ".0";
ipv4.SetBase(subnet.str().c_str(), "255.255.255.0");
interfaceAdjacencyList[i] = ipv4.Assign(deviceAdjacencyList[i]);
}
// Turn on global static routing
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
// Create a packet sink on the star "hub" to receive these packets
uint16_t port = 50000;
Address sinkLocalAddress(InetSocketAddress(Ipv4Address::GetAny(), port));
PacketSinkHelper sinkHelper("ns3::TcpSocketFactory", sinkLocalAddress);
ApplicationContainer sinkApp = sinkHelper.Install(serverNode);
sinkApp.Start(Seconds(1));
sinkApp.Stop(Seconds(10));
// Create the OnOff applications to send TCP to the server
OnOffHelper clientHelper("ns3::TcpSocketFactory", Address());
clientHelper.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
clientHelper.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
// normally wouldn't need a loop here but the server IP address is different
// on each p2p subnet
ApplicationContainer clientApps;
for (uint32_t i = 0; i < clientNodes.GetN(); ++i)
{
AddressValue remoteAddress(
InetSocketAddress(interfaceAdjacencyList[i].GetAddress(0), port));
clientHelper.SetAttribute("Remote", remoteAddress);
clientApps.Add(clientHelper.Install(clientNodes.Get(i)));
}
clientApps.Start(Seconds(1));
clientApps.Stop(Seconds(10));
// NetAnim output
AnimationInterface anim("tcp-star-server.xml");
anim.EnablePacketMetadata(true);
anim.UpdateNodeDescription(serverNode.Get(0), "Server");
anim.UpdateNodeColor(serverNode.Get(0), 0, 255, 0); // Green for server
anim.SetConstantPosition(serverNode.Get(0), 30, 30); // Center position for server
for (uint32_t i = 0; i < N - 1; ++i)
{
anim.UpdateNodeDescription(clientNodes.Get(i), "Client " + std::to_string(i + 1));
anim.UpdateNodeColor(clientNodes.Get(i), 255, 0, 0); // Red for clients
// Arrange clients in a circular pattern around the server
double angle = 2 * M_PI * i / (N - 1);
double x = 30 + 30 * cos(angle); // Radius of 30 units
double y = 30 + 30 * sin(angle);
anim.SetConstantPosition(clientNodes.Get(i), x, y);
}
NS_LOG_INFO("Run Simulation.");
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("Done.");
return 0;
}
Explaining the Magic: The AnimationInterface
The key to the visualization lies within the // NetAnim output
section of the code. Let's break it down:
#include "ns3/netanim-module.h"
: This line includes the necessary header file to use the NetAnim features.AnimationInterface anim("tcp-star-server.xml");
: This is the crucial first step. It creates anAnimationInterface
object namedanim
and tells it to write all the animation data to a file namedtcp-star-server.xml
. This XML file contains a time-stamped log of all network events, such as node creation, packet transmission, and node movement.anim.UpdateNodeDescription(...)
: This function sets a display name for a node in the animation. We're naming the central node "Server" and the others "Client 1", "Client 2", and so on.anim.UpdateNodeColor(...)
: To easily distinguish between the server and clients, we assign them different colors. We've made the server green (RGB: 0, 255, 0) and all the clients red (RGB: 255, 0, 0).anim.SetConstantPosition(...)
: Since our nodes are stationary, we explicitly set their positions on the animation canvas.The server is placed at coordinates (30, 30).
The client nodes are placed in a circle around the server using some simple trigonometry (
cos
andsin
). This ensures a clean, easy-to-understand star layout, regardless of the number of clients.
Building and Running the Simulation
Save the Code: Save the code above into a file named
tcp-star-server.cc
inside yourns-3-dev/scratch
directory.Build NS3: Open your terminal, navigate to your
ns-3-dev
directory, and run the build command:Bash
./ns3 build
Run the Simulation: Now, run the simulation. We'll use the
--nNodes
command-line argument to specify that we want 20 nodes (1 server and 19 clients).Bash
./ns3 run "scratch/tcp-star-server --nNodes=20"
After the simulation finishes, you will find a new file named
tcp-star-server.xml
in yourns-3-dev
directory. This is the animation file we need.
Visualizing with NetAnim
Launch NetAnim: Navigate to your NetAnim directory (usually
netanim-3.108
or similar within your NS3 installation) and launch the application.Bash
./NetAnim
Open the XML File: Once NetAnim is open, click the "Open" button or go to File > Open. Navigate to your
ns-3-dev
directory and select thetcp-star-server.xml
file you just created.You can now use the timeline slider at the top to play the simulation. You will see packets flowing from the red client nodes to the central green server node, providing a clear visual representation of the network traffic.
Subscribe to my newsletter
Read articles from Fathan Pranaya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
