TCP Data Transfer | Piggybacking & Pure Acknowledgement

TCP Data Transfer | Piggybacking & Pure Acknowledgement

When two computers talk to each other over a network, they don’t just fire data at each other and hope for the best. They need a reliable way to confirm that data actually arrived, in the right order, without corruption. This is where TCP (Transmission Control Protocol) comes in, and at the heart of its reliability mechanism lies the concept of acknowledgements.

In this article, we will explore how TCP handles data transfer, what acknowledgements are, and the difference between two important techniques: piggybacking and pure acknowledgement. We will build this understanding from first principles, using simple language, real-world analogies, diagrams, and practical examples from Linux, Cisco, and Python.

By the end of this article, you will understand:


1. A Quick Refresher: What Is TCP?

TCP is a connection-oriented, reliable, byte-stream transport layer protocol defined in RFC 793 and updated by many later RFCs. It sits at Layer 4 of the OSI model and Layer 4 (Transport) of the TCP/IP model.

Unlike UDP, which just sends packets and forgets about them, TCP guarantees:

  1. Reliable delivery — lost packets are retransmitted.
  2. Ordered delivery — packets are reassembled in the correct sequence even if they arrive out of order.
  3. Flow control — the sender doesn’t overwhelm the receiver’s buffer.
  4. Congestion control — the sender backs off when the network is congested.

All of these features depend on one core mechanism: acknowledgement (ACK) of received data.


2. Why Acknowledgements Are Necessary

Imagine you are sending a stack of letters to a friend through a postal service that sometimes loses mail. If your friend never tells you which letters arrived, you have no way of knowing whether to resend a lost letter. Acknowledgements solve exactly this problem in networking.

In TCP, every byte of data sent is assigned a sequence number. When the receiver gets a segment, it sends back an acknowledgement number, which tells the sender “I have successfully received all bytes up to this point; please send the next byte from here.”

This is called cumulative acknowledgement — a single ACK confirms receipt of everything up to a given byte, not just one specific packet.

The ACK Flag and Acknowledgement Number

Every TCP segment contains a header with:


3. Pure Acknowledgement

A pure acknowledgement is a TCP segment that contains only the ACK flag and acknowledgement number — no actual payload/data of its own. It exists purely to inform the sender that data has been received.

When Does Pure ACK Happen?

Pure ACKs typically occur when:

Characteristics of a Pure ACK

PropertyValue
Contains payload?No
Header size20 bytes (no options) to 60 bytes (with options)
ACK flagSet to 1
Sequence numberSame as previous segment sent (no new data)
PurposeConfirm receipt of previous segment(s)

Real-World Analogy

Think of pure ACK like a text message that just says “Got it 👍” — it doesn’t carry any new information for the other person, it simply confirms receipt.


4. Piggybacking

Piggybacking is an optimization technique where the acknowledgement for received data is attached to (piggybacked on) an outgoing data segment, instead of being sent as a separate, empty ACK packet.

This happens naturally in full-duplex, bidirectional communication — for example, in a Telnet or SSH session, or in an HTTP/2 stream where both client and server are exchanging data continuously.

Why Piggybacking Matters

Sending a separate ACK for every data segment wastes bandwidth and processing resources, especially in bidirectional traffic where both parties are already sending data anyway. Piggybacking reduces the number of packets on the wire by combining the “I got your data” message with “here is my data” message into a single TCP segment.

How Piggybacking Works — Step by Step

  1. Host A sends data to Host B.
  2. Host B receives Host A’s data and needs to send some data back to Host A anyway.
  3. Instead of sending a pure ACK immediately, Host B waits briefly (or immediately, if data is ready) and sends a single TCP segment containing:
    • Its own data (payload)
    • The ACK number acknowledging Host A’s data

This single segment now serves two purposes at once.

Mermaid Diagram: Piggybacking vs Pure ACK

sequenceDiagram
    participant A as Host A
    participant B as Host B

    Note over A,B: Pure Acknowledgement Scenario
    A->>B: Data Segment (Seq=100, Len=50)
    B-->>A: Pure ACK (Ack=150, no data)

    Note over A,B: Piggybacking Scenario
    A->>B: Data Segment (Seq=100, Len=50)
    B->>A: Data + ACK (Seq=200, Ack=150, Len=30)

In the first scenario, Host B has nothing to send, so it replies with an empty ACK. In the second scenario, Host B has data to send anyway, so it combines the ACK with its own data segment — this is piggybacking.


5. Delayed Acknowledgement and Its Relationship with Piggybacking

TCP implementations often use a technique called delayed ACK to increase the chances of piggybacking. Instead of acknowledging every single segment the instant it arrives, the receiver waits for a short period (typically up to 200ms, governed by a timer) to see if it has any outgoing data to piggyback the ACK onto.

Why Not Always Delay?

Delaying ACKs indefinitely would hurt performance because the sender’s congestion window depends on receiving timely ACKs to keep sending more data (this is closely tied to TCP’s sliding window mechanism). So there’s a tradeoff between efficiency (fewer packets via piggybacking) and responsiveness (timely ACKs to keep data flowing).


6. Sequence and Acknowledgement Numbers in Action

Let’s trace through a real example. Suppose Host A wants to send 300 bytes of data to Host B, using a Maximum Segment Size (MSS) of 100 bytes.

StepSender (A) ActionSeq NoData LengthReceiver (B) ActionAck No
1Send Segment 11000100Receives, buffers
2Send Segment 21100100Receives, buffers
3Send Segment 31200100Receives all, sends ACK1300

Here, Host B sent a cumulative ACK of 1300, meaning “I have received everything up to byte 1299; send me byte 1300 next.” If Host B had data of its own to send back at this point, it would attach ACK=1300 to that outgoing segment — piggybacking in action.


7. Linux Example: Observing ACKs with tcpdump

You can actually observe pure ACKs and piggybacked ACKs on a Linux system using tcpdump.

# Capture TCP traffic on interface eth0, showing sequence and ack numbers
sudo tcpdump -i eth0 -S -n tcp port 22

Sample output during an SSH session:

12:01:01.123456 IP 192.168.1.10.54321 > 192.168.1.20.22: Flags [P.], seq 1001:1051, ack 501, win 64240, length 50
12:01:01.223456 IP 192.168.1.20.22 > 192.168.1.10.54321: Flags [.], ack 1051, win 64240, length 0
12:01:01.323456 IP 192.168.1.20.22 > 192.168.1.10.54321: Flags [P.], seq 501:531, ack 1051, win 64240, length 30

Notice:

You can also inspect TCP statistics on Linux using:

# View TCP connection info including retransmissions and ACK stats
ss -ti

or

# Kernel-level TCP statistics counters
nstat -az | grep -i "Tcp\|DelayedACK"

8. Cisco Example: Observing TCP Behavior on a Router

While Cisco IOS devices are primarily concerned with routing rather than being TCP endpoints themselves, they do run TCP for management protocols like SSH, and you can inspect TCP-related behavior when the router itself is a TCP endpoint (e.g., for BGP sessions, which run over TCP port 179).

Router# show tcp brief all
TCB       Local Address           Foreign Address        (state)
6534A1F0  10.1.1.1.179            10.1.1.2.11002         ESTAB

To see detailed TCP statistics, including acknowledgements sent and received:

Router# show tcp statistics
Rcvd: 1200 total, 0 no port
      0 checksum error, 0 bad offset, 0 too short
      1150 packets (98000 bytes) in sequence
      50 dup packets (2000 bytes)
      0 out-of-order packets
Sent: 1180 total, 1150 data packets (97000 bytes)
      30 ack-only packets (0 data)

Notice the last line: “30 ack-only packets” — these are the pure acknowledgements. In contrast, most of the 1150 data packets that were sent to an established BGP peer would carry piggybacked ACKs, since BGP is bidirectional and both routers exchange routing updates continuously.

This matters in real-world scenarios like BGP session stability — if a router is sending many “ack-only” packets, it might indicate a mostly one-directional flow of routing updates or an asymmetric session load.


9. Python Example: Simulating Piggybacking and Pure ACK Behavior

While raw sockets in Python can be used to construct custom TCP-like behavior, a simpler educational approach is to build a small simulation using regular TCP sockets to observe how piggybacking naturally happens when both sides exchange data.

import socket
import threading
import time

def server():
    srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    srv.bind(("127.0.0.1", 9090))
    srv.listen(1)
    conn, addr = srv.accept()
    print("Server: connection established with", addr)

    data = conn.recv(1024)
    print("Server received:", data.decode())

    # Server has data to send back — this reply, at the TCP layer,
    # will carry the ACK for the client's data piggybacked in its header.
    conn.send(b"Hello back from server (piggybacked ACK at TCP layer)")
    conn.close()
    srv.close()

def client():
    time.sleep(1)
    cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    cli.connect(("127.0.0.1", 9090))
    cli.send(b"Hello from client")

    reply = cli.recv(1024)
    print("Client received:", reply.decode())
    cli.close()

t1 = threading.Thread(target=server)
t2 = threading.Thread(target=client)
t1.start()
t2.start()
t1.join()
t2.join()

Although the Python socket module operates above the TCP layer and doesn’t let us directly inspect ACK numbers (the OS kernel handles that), running this script while simultaneously capturing traffic with tcpdump -i lo -n tcp port 9090 will show you real piggybacked ACKs in the kernel’s TCP implementation — exactly like the Linux example in Section 7.


10. Comparison Table: Piggybacking vs Pure Acknowledgement

AspectPiggybackingPure Acknowledgement
Contains data payloadYesNo
Extra packet overheadLow (combined into one)Higher (separate packet needed)
Best suited forBidirectional/full-duplex trafficUnidirectional traffic
Typical use caseChat apps, SSH, BGP sessionsFile downloads, one-way streaming
Delay involvedSometimes uses delayed ACK timerSent as soon as timer expires or immediately
Bandwidth efficiencyHigherLower
Header overhead relative to dataAmortized over payloadFull 20+ byte header for zero data

11. Real-World Scenarios

Scenario 1: Web Browsing (Mostly Unidirectional)

When you download a large web page or file, your browser (client) sends very little data (just the HTTP GET request), while the server sends large amounts of data back. Since the client has little to say after the initial request, most of its outgoing segments are pure ACKs.

Scenario 2: SSH Interactive Session (Bidirectional)

In an interactive SSH session, you type commands and the server sends back command output continuously. Because both sides are frequently sending small chunks of data, piggybacking is very common — your keystrokes’ ACKs often ride along with terminal output being sent back.

Scenario 3: BGP Routing Sessions

As shown in the Cisco example, BGP peers exchange route updates over a long-lived TCP session. Since both routers are typically sending updates to each other, ACKs are frequently piggybacked onto route update messages, reducing unnecessary “ack-only” packets on the wire.


12. Best Practices

  1. Don’t disable delayed ACK blindly. While disabling delayed ACK can reduce latency in some real-time applications, it can also increase the number of pure ACK packets, adding overhead. Test before changing kernel parameters like TCP_QUICKACK on Linux.
  2. Monitor ACK-only packet counts on routers and servers (as shown in the Cisco show tcp statistics example) to understand traffic directionality.
  3. Use Nagle’s algorithm awareness. Nagle’s algorithm (which batches small outgoing packets) can interact with delayed ACK in a way that causes latency stalls; disable it (TCP_NODELAY) for latency-sensitive apps like gaming or real-time trading systems.
  4. Use packet capture tools (tcpdump, Wireshark) regularly during development to validate that your bidirectional protocols are actually benefiting from piggybacking, not generating excessive pure ACKs.
  5. Consider MSS and window sizing carefully, since larger data segments mean fewer overall segments and therefore fewer separate ACKs are needed in the first place.

13. Troubleshooting Common Issues

Issue: Excessive Pure ACK Traffic Slowing Down the Network

Symptom: Wireshark capture shows a huge number of zero-length ACK packets.

Cause: Often occurs in mostly unidirectional flows, or when delayed ACK is disabled, causing an ACK to be sent for almost every segment.

Fix: Verify whether TCP_QUICKACK is enabled unnecessarily on Linux:

# Check current quickack status is per-socket, but you can test with:
cat /proc/sys/net/ipv4/tcp_delack_min

Re-enable delayed ACK behavior for the application if latency isn’t critical, allowing more piggybacking opportunities.

Issue: Interactive Application Feels Laggy (e.g., SSH, Telnet)

Symptom: Noticeable delay between typing a character and seeing it echoed back.

Cause: This is the classic Nagle’s algorithm + delayed ACK interaction problem, where the sender waits for an ACK before sending small packets, and the receiver delays the ACK waiting for outgoing data.

Fix: Disable Nagle’s algorithm on latency-sensitive sockets:

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

Issue: BGP Session Flapping Correlated with High “ack-only” Packet Counts

Symptom: show tcp statistics on a Cisco router shows an unusually high ratio of ack-only packets to data packets.

Cause: May indicate one peer is not sending regular routing updates, causing the other side to fall back to pure ACKs, and potentially signaling a misconfigured route filter or a stalled BGP process.

Fix: Check show ip bgp summary for the peer’s state and verify route advertisement policies with show ip bgp neighbors advertised-routes.


14. Conclusion

TCP’s reliability hinges on the humble acknowledgement, but how that acknowledgement is sent — as a standalone pure ACK or bundled via piggybacking onto outgoing data — has real implications for network efficiency. Piggybacking reduces overhead in bidirectional communication by combining ACKs with data, while pure ACKs are necessary when there’s genuinely nothing else to send. Understanding this distinction helps network engineers, developers, and system administrators diagnose performance issues, tune delayed ACK behavior, and design more efficient network applications.


Further Reading

Exit mobile version