Study the Effect of Delayed ACKs on TCP Throughput
Performance and Latency Evaluation in a Point-to-Point NS-3 Link
Simulation Script (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;
}
Execution and Results
1. Running with Delayed ACKs (ON)
./ns3 run "tcp-delayed-ack --delayedAck=true"
|
| Output: Delayed ACKs Enabled |
2. Running with Immediate ACKs (OFF)
./ns3 run "tcp-delayed-ack --delayedAck=false"
|
| Output: Immediate ACKs (Delayed ACKs OFF) |
Wireshark Analysis
|
| Packet Trace via Wireshark |
Observations
- Throughput: Immediate ACKs yield slightly higher throughput (9.83 Mbps) compared to delayed ACKs (9.79 Mbps).
- Latency: Delayed ACKs exhibit lower average queuing delay (49 ms) compared to immediate ACKs (54 ms).
- Packet Count: Delayed ACK mode transmits fewer total packets (18,864 Rx / 18,873 Tx), making it significantly more packet-efficient by cutting reverse-channel acknowledgment traffic in half.
Conclusion
Delayed ACKs reduce TCP protocol overhead by generating one acknowledgment for every two received segments. While this decreases ACK contention on the reverse link and lowers overall packet processing latency, it can marginally reduce transmission throughput during unidirectional bulk transfers due to slightly slower congestion window expansion.
Comments
Post a Comment