Effect of Frame Size on Collision Probability and Throughput in a CSMA-Based LAN Using ns-3 Simulation | NS3 Project 18
Effect of Frame Size on Collision Probability and Throughput in a CSMA-Based LAN Using ns-3 Simulation
Aim :
To study the effect of frame size on
collision probability in a CSMA-based LAN by varying frame sizes and observing
the corresponding contention behavior and throughput using ns-3 simulation.
LLM Used
and Prompt
LLM Used: ChatGPT (GPT-5.4 Thinking)
Prompt
Used:
Write an ns-3 C++ program
runnable using ./ns3 run scratch/24BPS1151.cc to study the effect of frame size
on collision probability in a CSMA-based LAN. Use multiple sender nodes
connected via a CSMA channel to a receiver node. Vary frame sizes, estimate collision
probability using a contention-based proxy, compute throughput, generate output
files for plotting graphs, and include NetAnim support.
Topology
Description
The network consists of a shared CSMA LAN topology:
·
6 Sender
Nodes
·
1
Receiver Node
·
All nodes are connected using a single CSMA bus (shared medium)
Key Characteristics:
·
Channel Type: CSMA (shared
broadcast medium)
·
Data Rate: 10 Mbps
·
Channel Delay: 5 microseconds
·
Transport Protocol: UDP
·
Traffic Type: Random
(Poisson-like arrivals using exponential distribution)
Behavior:
·
All sender nodes transmit data
packets to a single receiver node.
·
Since the channel is shared,
multiple nodes may attempt transmission simultaneously, leading to contention.
Source
Code:
#include
"ns3/applications-module.h"
#include
"ns3/core-module.h"
#include
"ns3/csma-module.h"
#include
"ns3/internet-module.h"
#include
"ns3/mobility-module.h"
#include
"ns3/netanim-module.h"
#include
"ns3/network-module.h"
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("FrameSizeCollisionStudy");
// ------------------------------------------------------------
// Global statistics class
//
------------------------------------------------------------
class StudyStats
{
public:
void Configure(uint32_t frameSize, DataRate rate, Time channelDelay)
{
m_frameSize = frameSize;
m_rate = rate;
m_channelDelay = channelDelay;
m_attempts = 0;
m_collisionProxyCount = 0;
m_busyUntil = Seconds(0);
}
void RecordAttempt()
{
Time now = Simulator::Now();
m_attempts++;
// Approximate on-medium transmission time
uint32_t effectiveBytes = m_frameSize + 38;
// rough overhead
double txSeconds = (effectiveBytes * 8.0) /
m_rate.GetBitRate();
Time txTime = Seconds(txSeconds);
// Proxy: if a send attempt happens while
medium is already busy
if (now < m_busyUntil)
{
m_collisionProxyCount++;
}
Time start = (now > m_busyUntil) ? now : m_busyUntil;
m_busyUntil = start + txTime +
m_channelDelay;
}
uint64_t GetAttempts() const
{
return m_attempts;
}
uint64_t GetCollisionProxyCount() const
{
return m_collisionProxyCount;
}
double GetCollisionProxyProbability() const
{
if (m_attempts == 0)
{
return 0.0;
}
return
static_cast<double>(m_collisionProxyCount) /
static_cast<double>(m_attempts);
}
private:
uint32_t m_frameSize = 0;
DataRate m_rate = DataRate("10Mbps");
Time m_channelDelay = MicroSeconds(5);
uint64_t m_attempts = 0;
uint64_t m_collisionProxyCount = 0;
Time m_busyUntil = Seconds(0);
};
static StudyStats g_stats;
// ------------------------------------------------------------
// Custom traffic application
//
------------------------------------------------------------
class TrafficApp : public
Application
{
public:
TrafficApp() = default;
void Setup(Ptr<Socket> socket,
Address peer,
uint32_t packetSize,
uint32_t maxPackets,
double lambda)
{
m_socket = socket;
m_peer = peer;
m_packetSize = packetSize;
m_maxPackets = maxPackets;
m_lambda = lambda;
}
private:
virtual void StartApplication() override
{
m_running = true;
m_packetsSent = 0;
if (!m_socket)
{
return;
}
m_socket->Bind();
m_socket->Connect(m_peer);
m_exp =
CreateObject<ExponentialRandomVariable>();
m_exp->SetAttribute("Mean",
DoubleValue(1.0 / m_lambda));
Ptr<UniformRandomVariable> uv =
CreateObject<UniformRandomVariable>();
Time startOffset =
Seconds(uv->GetValue(0.001, 0.02));
m_sendEvent =
Simulator::Schedule(startOffset, &TrafficApp::SendPacket, this);
}
virtual void StopApplication() override
{
m_running = false;
if (m_sendEvent.IsPending())
{
Simulator::Cancel(m_sendEvent);
}
if (m_socket)
{
m_socket->Close();
}
}
void SendPacket()
{
if (!m_running || m_packetsSent >=
m_maxPackets)
{
return;
}
Ptr<Packet> packet = Create<Packet>(m_packetSize);
g_stats.RecordAttempt();
m_socket->Send(packet);
m_packetsSent++;
if (m_packetsSent < m_maxPackets)
{
ScheduleNextTx();
}
}
void ScheduleNextTx()
{
double nextGap = m_exp->GetValue();
m_sendEvent =
Simulator::Schedule(Seconds(nextGap), &TrafficApp::SendPacket, this);
}
Ptr<Socket> m_socket;
Address m_peer;
bool m_running = false;
uint32_t m_packetSize = 512;
uint32_t m_maxPackets = 0;
uint32_t m_packetsSent = 0;
double m_lambda = 100.0;
EventId m_sendEvent;
Ptr<ExponentialRandomVariable> m_exp;
};
//
------------------------------------------------------------
// Result structure
//
------------------------------------------------------------
struct Result
{
uint32_t frameSize;
uint64_t attempts;
uint64_t collisionProxyCount;
double collisionProxyProbability;
double throughputMbps;
uint64_t rxBytes;
};
// ------------------------------------------------------------
// Run one case
//
------------------------------------------------------------
Result
RunOneCase(uint32_t frameSize,
bool createAnim,
uint32_t nSenders,
double offeredPpsPerSender,
double simTimeSec)
{
NodeContainer nodes;
nodes.Create(nSenders + 1); // last node = receiver
// Attach a fixed mobility model for NetAnim
MobilityHelper mobility;
mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
mobility.Install(nodes);
CsmaHelper csma;
DataRate channelRate("10Mbps");
Time channelDelay = MicroSeconds(5);
csma.SetChannelAttribute("DataRate", DataRateValue(channelRate));
csma.SetChannelAttribute("Delay", TimeValue(channelDelay));
NetDeviceContainer devices = csma.Install(nodes);
InternetStackHelper internet;
internet.Install(nodes);
Ipv4AddressHelper ipv4;
ipv4.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign(devices);
uint16_t port = 9999;
Address sinkAddress(InetSocketAddress(interfaces.GetAddress(nSenders),
port));
PacketSinkHelper sinkHelper("ns3::UdpSocketFactory",
InetSocketAddress(Ipv4Address::GetAny(), port));
ApplicationContainer sinkApp = sinkHelper.Install(nodes.Get(nSenders));
sinkApp.Start(Seconds(0.0));
sinkApp.Stop(Seconds(simTimeSec));
g_stats.Configure(frameSize, channelRate, channelDelay);
for (uint32_t i = 0; i < nSenders; ++i)
{
Ptr<Socket> socket =
Socket::CreateSocket(nodes.Get(i), UdpSocketFactory::GetTypeId());
Ptr<TrafficApp> app = CreateObject<TrafficApp>();
app->Setup(socket, sinkAddress,
frameSize, 4000, offeredPpsPerSender);
nodes.Get(i)->AddApplication(app);
app->SetStartTime(Seconds(0.5));
app->SetStopTime(Seconds(simTimeSec -
0.2));
}
AnimationInterface* anim = nullptr;
if (createAnim)
{
anim = new
AnimationInterface("framesize-study-animation.xml", 50000);
for (uint32_t i = 0; i < nSenders; ++i)
{
anim->SetConstantPosition(nodes.Get(i), 10 + i * 20, 20);
anim->UpdateNodeDescription(nodes.Get(i), "Sender-" +
std::to_string(i));
anim->UpdateNodeColor(nodes.Get(i),
255, 0, 0);
}
anim->SetConstantPosition(nodes.Get(nSenders),
60, 80);
anim->UpdateNodeDescription(nodes.Get(nSenders),
"Receiver");
anim->UpdateNodeColor(nodes.Get(nSenders), 0, 255, 0);
}
Simulator::Stop(Seconds(simTimeSec));
Simulator::Run();
Ptr<PacketSink> sink =
DynamicCast<PacketSink>(sinkApp.Get(0));
uint64_t rxBytes = sink->GetTotalRx();
double throughputMbps = (rxBytes * 8.0) / (simTimeSec * 1000000.0);
Result r;
r.frameSize = frameSize;
r.attempts = g_stats.GetAttempts();
r.collisionProxyCount = g_stats.GetCollisionProxyCount();
r.collisionProxyProbability = g_stats.GetCollisionProxyProbability();
r.throughputMbps = throughputMbps;
r.rxBytes = rxBytes;
Simulator::Destroy();
if (anim)
{
delete anim;
}
return r;
}
//
------------------------------------------------------------
// Write output files
//
------------------------------------------------------------
void
WritePlotFiles(const
std::vector<Result>& results)
{
std::ofstream dat("framesize-results.dat");
dat << "#FrameSize CollisionProxyProbability ThroughputMbps
Attempts CollisionProxyCount RxBytes\n";
for (const auto& r : results)
{
dat << r.frameSize << "
"
<< std::fixed <<
std::setprecision(6) << r.collisionProxyProbability << "
"
<< std::fixed <<
std::setprecision(6) << r.throughputMbps << " "
<< r.attempts << "
"
<< r.collisionProxyCount <<
" "
<< r.rxBytes <<
"\n";
}
dat.close();
std::ofstream plt1("collision-vs-framesize.plt");
plt1 << "set terminal png size 1000,700\n";
plt1 << "set output 'collision-vs-framesize.png'\n";
plt1 << "set title 'Frame Size vs Collision Proxy Probability
in CSMA LAN'\n";
plt1 << "set xlabel 'Frame Size (bytes)'\n";
plt1 << "set ylabel 'Collision Proxy Probability'\n";
plt1 << "set grid\n";
plt1 << "plot 'framesize-results.dat' using 1:2 with
linespoints lw 2 pt 7 title 'Collision Proxy'\n";
plt1.close();
std::ofstream plt2("throughput-vs-framesize.plt");
plt2 << "set terminal png size 1000,700\n";
plt2 << "set output 'throughput-vs-framesize.png'\n";
plt2 << "set title 'Frame Size vs Throughput in CSMA
LAN'\n";
plt2 << "set xlabel 'Frame Size (bytes)'\n";
plt2 << "set ylabel 'Throughput (Mbps)'\n";
plt2 << "set grid\n";
plt2 << "plot 'framesize-results.dat' using 1:3 with
linespoints lw 2 pt 7 title 'Throughput'\n";
plt2.close();
}
//
------------------------------------------------------------
// Main
//
------------------------------------------------------------
int
main(int argc, char* argv[])
{
uint32_t nSenders = 6;
double offeredPpsPerSender = 150.0;
double simTimeSec = 10.0;
CommandLine cmd(__FILE__);
cmd.AddValue("nSenders", "Number of sender nodes",
nSenders);
cmd.AddValue("pps", "Offered packets/sec per
sender", offeredPpsPerSender);
cmd.AddValue("simTime", "Simulation time in
seconds", simTimeSec);
cmd.Parse(argc, argv);
std::vector<uint32_t> frameSizes = {128, 256, 512, 1024, 1500};
std::vector<Result> results;
std::cout << "\n===== CSMA Frame Size Study =====\n";
std::cout << "Senders: " << nSenders
<< ", Offered Load per
Sender: " << offeredPpsPerSender
<< " pps, Simulation
Time: " << simTimeSec << " s\n\n";
for (uint32_t i = 0; i < frameSizes.size(); ++i)
{
bool createAnim = (frameSizes[i] == 512);
// one representative animation case
Result r = RunOneCase(frameSizes[i],
createAnim, nSenders, offeredPpsPerSender, simTimeSec);
results.push_back(r);
std::cout << "FrameSize="
<< std::setw(4) << r.frameSize
<< " bytes |
Attempts=" << std::setw(8) << r.attempts
<< " |
BusyAttempts=" << std::setw(8) << r.collisionProxyCount
<< " |
CollisionProxy=" << std::fixed << std::setprecision(6)
<< r.collisionProxyProbability
<< " |
Throughput=" << std::fixed << std::setprecision(4) <<
r.throughputMbps
<< " Mbps\n";
}
WritePlotFiles(results);
std::cout << "\nOutput files generated:\n";
std::cout << "
framesize-results.dat\n";
std::cout << "
collision-vs-framesize.plt\n";
std::cout << "
throughput-vs-framesize.plt\n";
std::cout << "
framesize-study-animation.xml\n\n";
std::cout << "To generate graphs using gnuplot:\n";
std::cout << " gnuplot
collision-vs-framesize.plt\n";
std::cout << " gnuplot
throughput-vs-framesize.plt\n\n";
std::cout << "NOTE: ns-3 CSMA does not model true Ethernet
collisions.\n";
std::cout << "The reported collision value is a
contention-based proxy.\n";
return 0;
}
Animation Screenshots:
The animation shows multiple sender nodes
transmitting packets over a shared CSMA channel to a single receiver node. The
shared medium leads to contention among nodes.
Graph Screenshot(s)
Graph 2: Frame Size vs
Throughput
Throughput
Graph Explanation
The throughput initially
increases with frame size because larger frames carry more payload relative to
overhead. However, as frame size continues to increase, the channel remains
occupied for longer durations, increasing contention among nodes. This results
in diminishing returns or slight degradation in throughput at higher frame
sizes under heavy load conditions.
Graph 1: Frame Size vs Collision
Probability
Collision
Probability Graph Explanation
The graph shows that collision
probability increases with frame size. Larger frames occupy the shared medium
for a longer duration, which increases the likelihood that other nodes attempt
transmission while the channel is busy. This leads to higher contention levels.
At higher frame sizes, the collision probability approaches saturation due to
continuous channel occupancy under heavy traffic conditions.
Conclusion
From the experiment, it is
observed that frame size has a significant impact on collision behavior in a
CSMA-based LAN. As frame size increases, the duration for which the channel
remains occupied also increases, leading to higher chances of contention among
nodes. This results in an increase in collision probability. While larger
frames improve data efficiency by reducing overhead, excessive frame size can
negatively affect network performance due to increased contention. Therefore,
an optimal frame size must balance efficiency and collision probability.
Comments
Post a Comment