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 mai
n(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 A
CKs", 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(M
illiSeconds(200)));
     } else {
         // Disable delayed ACKs: ACK immediately every segment
         Config::SetDefault("ns3::TcpSocket::DelAckCount",
                            UintegerValue(1));
         Config::SetDefault("ns3::TcpSocket::DelAckTimeou
t",
                            TimeValue(MilliSeconds(0)));
     }
 
     // --- Topology: Sender --- p2p link --- Receiver ---
     NodeContainer nodes;
     nodes.Create(2);
 
     PointToPointHelper p2p;
     p2p.SetDeviceAttribute("DataRate", StringValue("10Mb
ps"));
     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));
     Applicati
onContainer 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<Ip
v4FlowClassifier>(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";
             s
td::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

  1. Throughput: Immediate ACKs result in slightly higher throughput (9.83 Mbps) than delayed ACKs (9.79 Mbps).

  1. Latency: Delayed ACKs result in lower delay (49 ms) than immediate ACKs (54 ms).

  1. 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

Popular posts from this blog

How to Create Ubuntu 24.04 Bootable USB Using Rufus [Step-by-Step Guide]

Installing ns3 in Ubuntu 22.04 | Complete Instructions

NS2 (NS-2.35) Installation in Ubuntu 11.10