TCP Connection & Data Segments Sockets: Fundamentals of TCP/IP Networks

 

TCP Connection & Data Segments
Chapter 58 | Sockets: Fundamentals of TCP/IP Networks โ€” Part 1 of 5
๐Ÿ“š TLPI Ch.58
๐Ÿ”Œ TCP/IP
๐Ÿ”จ Socket Programming

What is TCP?

TCP stands for Transmission Control Protocol. It is one of the two main transport protocols used on the Internet (the other being UDP). TCP provides a reliable, ordered, and error-checked delivery of data between two programs communicating over a network.

When you open a socket in Linux using SOCK_STREAM, you are using TCP under the hood. Think of TCP like a phone call โ€” before you talk, you dial and connect. Once connected, everything you say arrives in order, and the other side can hear it all clearly.

Key Terms in This Section

TCP Endpoint Connection Establishment Three-Way Handshake TCP Segment Checksum IP Datagram SOCK_STREAM Stream Socket

๐Ÿ”Œ TCP Endpoints โ€” Sender and Receiver

A TCP connection is always between two endpoints. Each endpoint is maintained by the TCP layer on that machine. One side is the sending TCP and the other is the receiving TCP.

TCP is bidirectional โ€” both sides can send and receive at the same time. But when we describe a specific data flow, we call one end the sender and the other the receiver for that direction.

๐Ÿ’ป
Application A
Sending TCP
DATA โ†’
โ† ACK
TCP Stream Socket
๐Ÿ’ป
Application B
Receiving TCP
Both ends maintain state information about the connection at the TCP layer

The TCP layer maintains state information at each endpoint โ€” things like how much data was sent, what was acknowledged, what the sequence numbers are, and the size of the receive buffer. This is why TCP is called a stateful protocol.

โœ… Connection Establishment โ€” The Three-Way Handshake

Before any data can be sent, TCP must establish a connection. This happens through a process called the three-way handshake.

During this handshake, both sides also exchange options โ€” for example, the maximum segment size (MSS) they support, whether they support window scaling, etc.

Client
โžก SYN (seq=x) ย ย  “I want to connect”
โฌ… SYN-ACK (seq=y, ack=x+1) ย ย  “OK, I’m ready”
โžก ACK (ack=y+1) ย ย  “Connected!”
๐Ÿ” Data exchange begins
Server
3 packets exchanged before any application data flows

The handshake ensures both sides are ready to communicate and have agreed on initial parameters. Only after the third step (ACK) is the connection considered established.

๐Ÿ“ฆ Packaging of Data in Segments

TCP does not send your data as one big blob. It breaks data into smaller chunks called segments. Each segment:

  • Contains a checksum โ€” a mathematical value used to detect transmission errors
  • Is transmitted inside a single IP datagram
  • Has a header with control information (sequence number, ACK number, flags, window size)

TCP Segment inside an IP Datagram
IP Header
20 bytes
TCP Header (20+ bytes)
Src Port
Dst Port
Seq Num
ACK Num
Flags
Checksum
Application Data
(payload)
The entire TCP segment (header + data) fits inside one IP datagram

The checksum covers both the header and data. When the receiver gets the segment, it recomputes the checksum. If the values don’t match, the segment is silently discarded (TCP then handles retransmission separately).

๐Ÿ’ป Code Example: Creating a TCP Stream Socket

In Linux, you create a TCP socket using socket() with SOCK_STREAM. Below is a minimal TCP client that connects to a server โ€” demonstrating the connection establishment phase in real code.

/* tcp_client.c - minimal TCP connection example */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_IP   "127.0.0.1"
#define SERVER_PORT 8080
#define MSG         "Hello from TCP client\n"

int main(void)
{
    int sockfd;
    struct sockaddr_in srv_addr;
    ssize_t bytes_sent;

    /*
     * Step 1: Create a TCP socket (SOCK_STREAM = TCP)
     * AF_INET  = IPv4
     * SOCK_STREAM = reliable, ordered, connection-based (TCP)
     * 0 = let OS choose protocol (TCP for SOCK_STREAM)
     */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    /* Step 2: Fill in server address */
    memset(&srv_addr, 0, sizeof(srv_addr));
    srv_addr.sin_family      = AF_INET;
    srv_addr.sin_port        = htons(SERVER_PORT);  /* host to network byte order */
    srv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

    /*
     * Step 3: connect() triggers the THREE-WAY HANDSHAKE
     *   - Kernel sends SYN to server
     *   - Waits for SYN-ACK
     *   - Sends final ACK
     * After connect() returns, TCP connection is ESTABLISHED
     */
    if (connect(sockfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) == -1) {
        perror("connect");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    printf("TCP connection established to %s:%d\n", SERVER_IP, SERVER_PORT);

    /* Step 4: Send data โ€” TCP segments this into one or more segments */
    bytes_sent = write(sockfd, MSG, strlen(MSG));
    if (bytes_sent == -1) {
        perror("write");
    } else {
        printf("Sent %zd bytes\n", bytes_sent);
    }

    /* Step 5: Close โ€” triggers FIN handshake (connection teardown) */
    close(sockfd);
    return 0;
}
/* tcp_server.c - minimal TCP server to pair with above client */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT    8080
#define BACKLOG 5
#define BUFSIZE 256

int main(void)
{
    int listenfd, connfd;
    struct sockaddr_in srv_addr, cli_addr;
    socklen_t cli_len = sizeof(cli_addr);
    char buf[BUFSIZE];
    ssize_t n;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1) { perror("socket"); exit(EXIT_FAILURE); }

    memset(&srv_addr, 0, sizeof(srv_addr));
    srv_addr.sin_family      = AF_INET;
    srv_addr.sin_port        = htons(PORT);
    srv_addr.sin_addr.s_addr = INADDR_ANY; /* accept on all interfaces */

    /* bind: attach socket to port */
    if (bind(listenfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) == -1) {
        perror("bind"); exit(EXIT_FAILURE);
    }

    /* listen: mark socket as passive; ready to accept connections */
    if (listen(listenfd, BACKLOG) == -1) {
        perror("listen"); exit(EXIT_FAILURE);
    }

    printf("Server listening on port %d...\n", PORT);

    /*
     * accept() completes the three-way handshake from the server side.
     * It returns a NEW socket (connfd) for this specific connection.
     * listenfd keeps accepting new clients.
     */
    connfd = accept(listenfd, (struct sockaddr *)&cli_addr, &cli_len);
    if (connfd == -1) { perror("accept"); exit(EXIT_FAILURE); }

    printf("Client connected!\n");

    n = read(connfd, buf, BUFSIZE - 1);
    if (n > 0) {
        buf[n] = '\0';
        printf("Received: %s", buf);
    }

    close(connfd);
    close(listenfd);
    return 0;
}

Compile and run:

# Terminal 1: Start server
gcc tcp_server.c -o tcp_server
./tcp_server

# Terminal 2: Run client
gcc tcp_client.c -o tcp_client
./tcp_client

๐Ÿ…พ Interview Questions โ€” TCP Connection & Segments
Q1. What is the three-way handshake and why is it needed?

The three-way handshake (SYN โ†’ SYN-ACK โ†’ ACK) establishes a TCP connection. It is needed to: (1) ensure both sides are ready, (2) synchronize initial sequence numbers, and (3) exchange connection parameters like MSS and window size. Without it, data could be sent to a side that is not ready.

Q2. What is a TCP segment? How does it differ from a TCP stream?

A TCP segment is the unit of data at the TCP layer โ€” a chunk of data with a TCP header. A TCP stream is the logical byte-stream abstraction that the application sees. The stream is split into segments for transmission; the receiver reassembles them back into the original byte order before delivering to the application.

Q3. What does SOCK_STREAM mean in socket()?

SOCK_STREAM requests a reliable, connection-oriented, byte-stream socket. On most systems this maps to TCP over IPv4/IPv6. It guarantees ordered delivery, no duplication, and error detection.

Q4. Why does TCP use checksums?

Checksums allow end-to-end detection of data corruption during transmission (bit errors in links, RAM errors in routers). If a segment’s checksum does not match, TCP discards it silently. TCP then handles recovery through retransmission.

Q5. What options can be exchanged during TCP connection establishment?

Common TCP options exchanged during the handshake include: Maximum Segment Size (MSS), Window Scale factor (for large windows), SACK (Selective Acknowledgement) permitted, and Timestamps option for RTT measurement and PAWS (Protection Against Wrapped Sequence numbers).

Q6. What is the difference between listenfd and connfd returned by accept()?

listenfd is the passive socket โ€” it only receives connection requests. connfd is a new socket created by accept() specifically for the newly accepted client connection. The server uses connfd to exchange data with that client while listenfd continues accepting new connections.

Next: ACK, Retransmissions & Timeouts
Learn how TCP handles lost segments, delayed ACKs, and dynamic timeout calculation

Part 2 โ†’ EmbeddedPathashala

Leave a Reply

Your email address will not be published. Required fields are marked *