TCP Working: 3-Way Handshake & Reliable Communication
What Happens Without Rules? Pure Chaos, Bhai
Imagine you're in Chandni Chowk during Diwali sale season. You're trying to tell your friend something important, but there are 5,000 people between you, all shouting at the same time. You yell "Meet me at the samosa stall!" but:
Maybe they only hear "Meet me at the..." and miss the location. Maybe they hear "...at the samosa stall!" but miss that you're talking to them. Maybe they hear it perfectly but in the wrong order: "Samosa at the me meet stall!" Maybe someone else hears it and shows up at the samosa stall instead.
This is what happens when you send data across the internet without rules. Packets get lost. They arrive out of order. They get corrupted. They reach the wrong destination. It's complete anarchy, like trying to form a queue at a government office where the concept of queuing doesn't exist.
Your computer could send a packet, and it just disappears into the void. The network doesn't care. Routers along the way are busy handling millions of other packets. Your packet might get dropped because a router's buffer was full. It might take a detour through three extra networks and arrive after packets that were sent later. It might get partially corrupted by electrical interference.
The underlying internet infrastructure (IP layer) is "best effort." It tries to deliver your packets, but it makes no promises. It's like telling your friend "I'll try to come to your wedding" which everyone knows means "I'm probably not coming."
Enter TCP: The Overprotective Parent of Protocols
TCP (Transmission Control Protocol) exists to solve this chaos. It's the protocol that sits on top of the unreliable internet and builds a reliable, ordered, error-checked communication channel.
Think of TCP as that one friend who confirms everything three times. "Did you get my message? Reply 'yes' if you got it. Why haven't you replied? Are you ignoring me? Should I send it again?"
TCP was designed to solve specific problems that arise from the internet's inherent unreliability.
Problems TCP is Designed to Solve
Problem 1: Packets Get Lost
The internet is a shared network. Routers have limited buffer space. When a router receives more packets than it can handle, it just drops some. Like when the local train is full and you can't board, except the train doesn't feel bad about it and doesn't send another train for you specifically.
TCP's solution: Every packet sent must be acknowledged by the receiver. If the sender doesn't receive an acknowledgment within a certain time, it assumes the packet was lost and sends it again. It's like WhatsApp blue ticks, but actually reliable.
Problem 2: Packets Arrive Out of Order
Different packets might take different routes across the internet. Packet 1 might go through Mumbai, Bangalore, and Delhi. Packet 2 might go through Kolkata, Chennai, and Delhi. Packet 2 might arrive first even though it was sent second.
If you're sending a message "Send money urgently" and it arrives as "Money send urgently," the meaning changes. If you're sending a video file and the frames arrive scrambled, you get digital chaos.
TCP's solution: Every packet is assigned a sequence number. The receiver uses these numbers to reassemble packets in the correct order, no matter what order they arrive in. It's like giving each person in a queue a token number so they get served in order even if they wander around while waiting.
Problem 3: Packets Get Corrupted
Electrical interference, faulty hardware, or cosmic rays (yes, really) can flip bits in packets as they travel. A packet saying "Transfer 100 rupees" might get corrupted to "Transfer 900 rupees." Not good.
TCP's solution: Every packet includes a checksum, which is a mathematical fingerprint of the data. The receiver recalculates this checksum and verifies it matches. If not, the packet is corrupted and is discarded. The sender will eventually retransmit it because no acknowledgment was received.
Problem 4: Duplicate Packets
Due to retransmissions and network quirks, the same packet might arrive multiple times. Imagine sending "Delete my account" and it arrives twice, so your account gets deleted, then... well, you can't delete it again, but you see the problem.
TCP's solution: Those sequence numbers also help identify duplicates. If a packet with sequence number 42 arrives twice, the receiver recognizes it's a duplicate and ignores the second copy.
Problem 5: Network Congestion
If senders blast data at full speed without checking if the network can handle it, they create congestion. Like everyone trying to exit a stadium through one gate at the same time. The result? Massive packet loss, which leads to retransmissions, which creates more congestion. Death spiral.
TCP's solution: Flow control and congestion control. The receiver tells the sender how much data it can handle. The sender monitors packet loss and adjusts its transmission rate accordingly. It's like the traffic police at Silk Board junction, except it actually works.
Problem 6: No Way to Know When Communication Starts or Ends
With UDP, you just start sending. The receiver has no idea if this is the start of a message, the middle, or the end. It's like walking into the middle of a Bollywood movie and trying to figure out if the hero and heroine are getting married or divorced in this scene.
TCP's solution: Explicit connection establishment and termination. Both sides agree to start communicating (handshake) and agree to stop (connection close). There's a clear beginning, middle, and end.
The TCP 3-Way Handshake: "Hello, Can We Talk?"
Before TCP sends any actual data, both sides must establish a connection. This is the famous three-way handshake, which sounds like a secret greeting but is actually just two computers being overly cautious.
The handshake solves a fundamental problem: both sides need to agree that they're ready to communicate, they need to exchange initial sequence numbers, and they need to allocate resources for the connection.
Think of it like calling your friend's landline in the early 2000s:
You dial. The phone rings on their end. They pick up and say "Hello?" You say "Hi, is Rahul there? This is Amit." They say "Yes, this is Rahul. Hi Amit." Now you can start the actual conversation.
The TCP handshake is similar, just more formal and with more paranoia.
Step-by-Step: The Three-Way Handshake
Let's say your computer (the client) wants to connect to a web server to load a webpage. Here's what happens:
Step 1: Client Sends SYN
Your computer sends a packet with the SYN flag set. SYN stands for "synchronize," but you can think of it as "Hey, I want to start a conversation."
This packet contains an initial sequence number (ISN), let's say 1000. This number is randomly chosen for security reasons. The client is essentially saying "I'm starting my packet numbering at 1000."
At this point, the client enters a state called SYN-SENT. It's waiting for the server to respond.
Real-world equivalent: You walk up to a shop and say "Bhaiya, suniye." You've initiated contact, but you don't know if he heard you or if he's willing to serve you.
Step 2: Server Sends SYN-ACK
If the server is listening and willing to accept connections, it sends back a packet with both the SYN and ACK flags set.
The ACK (acknowledge) flag says "I got your SYN." The acknowledgment number is set to the client's sequence number plus one, in this case 1001. The server is saying "I received your message starting at 1000, and I'm expecting your next data to start at 1001."
The SYN flag is the server's own synchronization. The server picks its own initial sequence number, let's say 5000. It's saying "I'm starting my packet numbering at 5000."
The server enters a state called SYN-RECEIVED. It has responded but is waiting for final confirmation.
Real-world equivalent: The shopkeeper turns around and says "Haan bhai, bolo, kya chahiye?" He's acknowledged you and indicated he's ready to do business, and he's also given you his attention number (5000).
Step 3: Client Sends ACK
Your computer receives the SYN-ACK. It now knows the server is ready and knows the server's starting sequence number (5000).
Your computer sends a final ACK packet. The acknowledgment number is set to the server's sequence number plus one, in this case 5001. The client is saying "I got your response starting at 5000, and I'm expecting your next data to start at 5001."
The sequence number in this packet is 1001 because the client is following the sequence it started.
The client enters an ESTABLISHED state. Both sides now consider the connection open and ready for data transfer.
When the server receives this ACK, it also enters ESTABLISHED state.
Real-world equivalent: You say "Ek chai dena" confirming that you heard him and are ready to order. Now actual business can begin.
Why Three Steps? Why Not Two?
You might wonder, why not just SYN and SYN-ACK? Why does the client need to send that final ACK?
The problem is that network delays are unpredictable. Imagine:
Client sends SYN. This packet gets delayed in the network for some reason. Client thinks the packet was lost, so it sends another SYN. The second SYN reaches the server, server sends SYN-ACK, connection is established. They communicate, then close the connection. Now the first SYN (which was delayed) finally arrives at the server. The server thinks it's a new connection request and sends SYN-ACK. Without the third step, the server would think a connection is open, but the client has moved on with its life.
The three-way handshake prevents this because the server waits for the final ACK before considering the connection fully established. If that delayed SYN arrived and the server sent SYN-ACK, but never received the final ACK, it would realize this was a ghost from the past and discard it.

How Data Transfer Works: Sequence Numbers and Acknowledgments
Once the connection is established, actual data transfer begins. This is where TCP's reliability mechanisms really shine.
Sequence Numbers: Keeping Track of Bytes
Every byte of data sent over TCP is assigned a sequence number. If the client's initial sequence number was 1000, and it sends 100 bytes of data, those bytes are numbered 1001 to 1100. The next packet would start at sequence number 1101.
Sequence numbers serve multiple purposes. They allow the receiver to reassemble data in the correct order. They help identify which data is being acknowledged. They help detect duplicates and missing data.
Let's say you're sending a file that's 10,000 bytes long. The sender breaks it into packets. Packet 1 has sequence number 1001 and contains 1,000 bytes (1001-2000). Packet 2 has sequence number 2001 and contains 1,000 bytes (2001-3000). And so on.
If packet 3 (sequence 3001-4000) gets lost but packet 4 (sequence 4001-5000) arrives, the receiver knows something is missing because there's a gap in the sequence numbers.
Acknowledgment Numbers: Confirming Receipt
For every data packet received, the receiver sends back an acknowledgment. The ACK number indicates the next byte the receiver expects to receive.
If the receiver gets packet 1 (bytes 1001-2000), it sends ACK 2001, meaning "I got everything up to byte 2000, now I'm expecting byte 2001 next."
If the receiver gets packets 1, 2, and 3 (bytes 1001-4000), it sends ACK 4001.
These acknowledgments might be sent in separate packets, or they might be piggybacked on data flowing in the opposite direction. If the receiver is also sending data back, it includes the ACK in those data packets to save bandwidth. Efficient, like carpooling.
Sliding Window: Not Waiting Forever Like a Government Office
Here's the clever part: TCP doesn't send one packet and then wait for its acknowledgment before sending the next one. That would be incredibly slow, like a restaurant where the waiter takes one person's order, goes to the kitchen, comes back with that dish, serves it, waits for them to finish eating, and only then takes the next person's order.
Instead, TCP uses a sliding window. The sender can send multiple packets before receiving acknowledgments, up to a certain limit (the window size).
Let's say the window size is 4 packets. The sender can send packets 1, 2, 3, and 4 without waiting for acknowledgments. As soon as it receives ACK for packet 1, the window "slides" forward, and it can now send packet 5. The window is now packets 2, 3, 4, 5.
This keeps the network pipe full and dramatically improves throughput. It's like the assembly line approach versus the traditional craftsman approach.
The window size is dynamically adjusted based on network conditions and the receiver's capacity. If the receiver is getting overwhelmed, it tells the sender to slow down by advertising a smaller window size.
How TCP Ensures Reliability: The Paranoia Pays Off
Handling Packet Loss
Let's say the sender transmits packets 1, 2, 3, 4, and 5. But packet 3 gets lost in the network. Here's what happens:
The sender sends packets 1, 2, 3, 4, 5. The receiver gets packets 1 and 2, sends ACK 3001 (expecting packet 3 next). Packet 3 never arrives. The receiver gets packet 4, but there's a gap in the sequence. It still sends ACK 3001 because it's still waiting for packet 3. The receiver gets packet 5, still missing packet 3. It again sends ACK 3001.
The sender is now receiving multiple ACKs for 3001. This is called a duplicate ACK. When the sender receives three duplicate ACKs for the same sequence number, it realizes that packet must have been lost. It immediately retransmits packet 3 without waiting for a timeout. This is called fast retransmit.
Alternatively, if no duplicate ACKs arrive, the sender has a retransmission timer. If it doesn't receive an ACK for packet 3 within a certain time, it assumes the packet was lost and retransmits it. This timeout is dynamically calculated based on network conditions.
Once packet 3 arrives, the receiver can now deliver packets 3, 4, and 5 to the application in order, and sends ACK 6001.
Handling Corruption
Every TCP packet includes a checksum calculated over the header and data. When a packet arrives, the receiver recalculates the checksum. If it doesn't match, the packet is silently discarded. No ACK is sent. From the sender's perspective, it's as if the packet was lost, so the retransmission mechanisms kick in.
The checksum isn't perfect (it can miss certain types of errors), but it catches most corruption. For critical applications, higher-layer protocols add their own error detection.
Handling Out-of-Order Delivery
If packets arrive out of order, TCP buffers them and waits for the missing pieces. Once all packets up to a certain point have arrived, TCP delivers them to the application in the correct order.
The application never sees out-of-order data. From the application's perspective, it's as if data arrived in a perfect stream, even though the underlying network delivered packets in complete chaos.
It's like watching a movie on a streaming service. Behind the scenes, video chunks might arrive out of order, but the player buffers and reorders them so you see a smooth, sequential video.
Handling Duplicates
If the same packet arrives twice (maybe a retransmission wasn't actually needed, or network weirdness duplicated it), the sequence number allows the receiver to detect this. The receiver simply discards the duplicate and doesn't deliver it to the application.
Flow Control: Not Overwhelming the Receiver
Imagine you're dictating notes to someone who's writing by hand. If you speak too fast, they can't keep up, they miss information, and they have to keep asking you to repeat things. Inefficient.
TCP implements flow control to prevent the sender from overwhelming the receiver. The receiver advertises a receive window in every ACK packet. This window tells the sender how much buffer space the receiver has available.
If the receiver's buffer is full because the application is slow to read the data, it advertises a window size of zero. The sender must stop transmitting until the receiver advertises a non-zero window again.
This prevents data loss at the receiver due to buffer overflow. It's like the receiver saying "Zara ruko, main likh raha hoon" (Wait a bit, I'm writing).
Congestion Control: Not Overwhelming the Network
Flow control handles the receiver's capacity. Congestion control handles the network's capacity.
If senders transmit too aggressively, they can overwhelm routers in the network. Routers start dropping packets, which leads to retransmissions, which creates more traffic, which creates more congestion. It's a feedback loop that can bring networks to their knees.
TCP implements several congestion control algorithms. The basic idea: start slow, gradually increase transmission rate, and back off when packet loss is detected.
Slow start: When a connection begins, start with a small congestion window (just a few packets). For each ACK received, increase the window size exponentially. This quickly ramps up to the available bandwidth.
Congestion avoidance: Once a threshold is reached, increase the window size more slowly (linearly).
Fast recovery: When packet loss is detected via duplicate ACKs, reduce the window size but not all the way back to the start. The network is congested but not completely overloaded, so we can back off partially.
Timeout: If a timeout occurs (more severe than just a few lost packets), assume serious congestion. Reset the congestion window to the minimum and start over.
These mechanisms mean TCP automatically adapts to network conditions. On a fast, uncongested network, it ramps up quickly. On a slow or congested network, it backs off. All without the application needing to know anything about network conditions.
It's like automatic transmission in a car. You don't manually shift gears based on engine speed and road conditions. The system handles it for you.

How a TCP Connection is Closed: The Polite Goodbye
Just as TCP has a formal handshake to start a connection, it has a formal process to close one. Both sides need to agree to close because TCP connections are full-duplex (data flows in both directions independently).
The Four-Way Handshake (Yes, Four This Time)
Let's say the client wants to close the connection after finishing its work:
Step 1: Client Sends FIN
The client sends a packet with the FIN flag (finish) set. This means "I have no more data to send." The client enters FIN-WAIT-1 state.
Important: The client is done sending, but it can still receive data from the server. It's like saying "I'm done talking, but I'll still listen if you have something to say."
Step 2: Server Sends ACK
The server receives the FIN and sends an ACK. It's acknowledging "I got your FIN, I understand you're done sending." The server enters CLOSE-WAIT state. The client enters FIN-WAIT-2 state.
At this point, the connection is half-closed. The client can't send more data, but the server can still send data to the client if it needs to.
Step 3: Server Sends FIN
When the server is also done (maybe it finishes sending its last bits of data), it sends its own FIN. The server is saying "I'm also done sending." The server enters LAST-ACK state.
Step 4: Client Sends ACK
The client receives the server's FIN and sends a final ACK. The client enters TIME-WAIT state. When the server receives this ACK, it closes the connection immediately.
The client waits in TIME-WAIT for a period (typically 2 times the maximum segment lifetime, around 1-4 minutes) before fully closing. This ensures that if the final ACK was lost, the client can retransmit it when the server retransmits the FIN.
After the timer expires, the client also closes the connection fully.
Why Four Steps Instead of Three?
Unlike the opening handshake, closing requires four steps because each direction of the connection must be closed independently.
When the client sends FIN, it's closing the client-to-server direction. But the server might still have data to send in the server-to-client direction. Only when the server also sends FIN is the entire connection closed.
It's like a phone conversation where one person says "I have to go now" but the other person says "Wait, one more thing!" The first person stops talking but keeps listening. When the second person is also done, they both hang up.
Abrupt Connection Close: The RST Flag
Sometimes connections need to be closed immediately without the polite four-way handshake. This happens when something goes wrong or when one side doesn't want to wait.
A RST (reset) packet immediately terminates the connection. No acknowledgments, no waiting, just instant termination. It's like hanging up mid-conversation.
RST is sent in error conditions like receiving a packet for a connection that doesn't exist, or when an application crashes and the OS needs to clean up connections, or when a firewall forcibly closes a connection.
The Complete TCP Lifecycle: Birth to Death
Let's trace the complete lifecycle of a TCP connection:
Three-way handshake establishes the connection. Both sides are now in ESTABLISHED state. Data flows in both directions. Sequence numbers increment with each byte sent. Acknowledgments flow back confirming receipt. Retransmissions handle lost packets. Flow control and congestion control adjust transmission rates. Eventually, one side decides to close. Four-way handshake tears down the connection. Both sides enter CLOSED state. The connection is dead.
The entire process is transparent to the application. When you write code that opens a TCP socket, sends data, and closes it, all this complexity happens automatically. The application just sees a reliable byte stream, like reading and writing to a file.
Why All This Complexity?
You might think "This is insanely complicated. Why not just send packets and hope for the best like UDP?"
The answer is that building reliable communication on top of an unreliable network is genuinely hard. The internet is chaotic. Packets get lost, delayed, duplicated, corrupted, and reordered all the time. Without TCP's mechanisms, every application would need to implement its own reliability, and most would do it poorly.
TCP handles all this complexity once, correctly, in the operating system. Applications get a simple abstraction: a reliable, ordered byte stream. They don't need to worry about packet loss, retransmissions, flow control, congestion control, or any of this.
It's like using a taxi versus walking. Walking requires you to handle navigation, traffic, weather, and physical exhaustion. A taxi handles all that for you. You just say where you want to go and trust that you'll get there safely.
TCP is the taxi of the internet. It's complicated under the hood, but that complexity exists so applications can be simple.
The Takeaway: TCP is Your Reliable Friend
TCP is designed to solve the problems of communicating over an unreliable network. It ensures data arrives completely, correctly, and in order, even when the underlying network is dropping, delaying, and corrupting packets.
The three-way handshake establishes a connection and synchronizes sequence numbers. Sequence numbers and acknowledgments track data and confirm receipt. Retransmission mechanisms handle packet loss. Checksums detect corruption. Buffering and ordering handle out-of-order delivery. Flow control prevents overwhelming the receiver. Congestion control prevents overwhelming the network. The four-way handshake politely closes connections.
All of this happens automatically. When you use TCP in your applications, you get reliability without having to think about it. You just open a socket, read and write data, and close the socket. TCP handles the rest.
Next time you browse a website, send an email, or download a file, remember that underneath it all, TCP is working tirelessly to ensure every byte arrives safely. It's the unsung hero of the internet, the responsible friend who makes sure everyone gets home safely after the party, even if it takes three confirmation messages and a safety check to do it.



