Study the effect of delayed ACKs on TCP throughput in a point-to-point link | NS3 Project 26
Study the effect of delayed ACKs on TCP throughput in a point-to-point link.
tcp-delayed-ack.cc
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/flow-monitor-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("TcpDelayedAckStudy");
int main(int argc, char *argv[]) {
bool delayedAck = true;
uint32_t delayedAckCount = 2; // ACK every N segments
std::string tcpVariant = "TcpNewReno";
double simTime = 10.0;
CommandLine cmd;
cmd.AddValue("delayedAck", "Enable delayed ACKs", delayedAck);
cmd.AddValue("delayedAckCount", "Segments before ACK", delayedAckCount);
cmd.Parse(argc, argv);
// --- TCP Configuration ---
Config::SetDefault("ns3::TcpL4Protocol::SocketType",
StringValue("ns3::" + tcpVariant));
if (delayedAck) {
Config::SetDefault("ns3::TcpSocket::DelAckCount",
UintegerValue(delayedAckCount));
Config::SetDefault("ns3::TcpSocket::DelAckTimeout",
TimeValue(MilliSeconds(200)));
} else {
// Disable delayed ACKs: ACK immediately every segment
Config::SetDefault("ns3::TcpSocket::DelAckCount",
UintegerValue(1));
Config::SetDefault("ns3::TcpSocket::DelAckTimeout",
TimeValue(MilliSeconds(0)));
}
// --- Topology: Sender --- p2p link --- Receiver ---
NodeContainer nodes;
nodes.Create(2);
PointToPointHelper p2p;
p2p.SetDeviceAttribute("DataRate", StringValue("10Mbps"));
p2p.SetChannelAttribute("Delay", StringValue("20ms")); // 40ms RTT base
NetDeviceContainer devices = p2p.Install(nodes);
// --- Internet Stack ---
InternetStackHelper stack;
stack.Install(nodes);
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = address.Assign(devices);
// --- Bulk Send Application (TCP sender) ---
uint16_t port = 9;
BulkSendHelper source("ns3::TcpSocketFactory",
InetSocketAddress(interfaces.GetAddress(1), port));
source.SetAttribute("MaxBytes", UintegerValue(0)); // unlimited
source.SetAttribute("SendSize", UintegerValue(1460)); // MSS
ApplicationContainer sourceApps = source.Install(nodes.Get(0));
sourceApps.Start(Seconds(1.0));
sourceApps.Stop(Seconds(simTime));
// --- Sink Application ---
PacketSinkHelper sink("ns3::TcpSocketFactory",
InetSocketAddress(Ipv4Address::GetAny(), port));
ApplicationContainer sinkApps = sink.Install(nodes.Get(1));
sinkApps.Start(Seconds(0.0));
sinkApps.Stop(Seconds(simTime + 1));
// --- Flow Monitor ---
FlowMonitorHelper flowMonitor;
Ptr<FlowMonitor> monitor = flowMonitor.InstallAll();
// --- PCAP Traces ---
p2p.EnablePcapAll("tcp-delayed-ack");
Simulator::Stop(Seconds(simTime + 1));
Simulator::Run();
// --- Print Results ---
monitor->CheckForLostPackets();
Ptr<Ipv4FlowClassifier> classifier =
DynamicCast<Ipv4FlowClassifier>(flowMonitor.GetClassifier());
FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
for (auto &flow : stats) {
Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(flow.first);
if (t.destinationPort == port) {
double throughput =
flow.second.rxBytes * 8.0 / (simTime - 1.0) / 1e6;
std::cout << "==============================\n";
std::cout <<"Delayed ACK: "<<(delayedAck?"ON":"OFF")<< "\n";
std::cout << "Throughput: " << throughput << " Mbps\n";
std::cout <<"Tx Packets: " << flow.second.txPackets << "\n";
std::cout <<"Rx Packets: " << flow.second.rxPackets << "\n";
std::cout << "Avg Delay: "
<< flow.second.delaySum.GetMilliSeconds() /
flow.second.rxPackets
<< " ms\n";
std::cout << "==============================\n";
}
}
Simulator::Destroy();
return 0;
}
Running with delayed ACKs:
./ns3 run "tcp-delayed-ack --delayedAck=true"
Running with immediate ACKs:
./ns3 run "tcp-delayed-ack –delayedAck=false"
Wireshark
Observations
Throughput: Immediate ACKs result in slightly higher throughput (9.83 Mbps) than delayed ACKs (9.79 Mbps).
Latency: Delayed ACKs result in lower delay (49 ms) than immediate ACKs (54 ms).
Packet count: Delayed ACK has a lower TX packet count (18873) than immediate ACKs (18864). This makes it more packet-efficient.
Conclusion
Delayed ACKs reduce TCP protocol overhead by sending one ACK for every two segments. This reduces latency and improves packet efficiency, but this does not always improve throughput and can reduce it in unidirectional bulk transfers.
Comments
Post a Comment