Chapter 58 at a Glance
This page summarizes everything from Chapter 58 and brings together interview questions from all parts. Use this for last-minute revision before an interview or as a reference during study.
| Layer | Protocol | PDU Name | Address Used | Key Properties |
|---|---|---|---|---|
| Application | HTTP, FTP, DNS, SSHโฆ | Message | โ | Your program lives here |
| Transport | TCP / UDP | Segment / Datagram | Port numbers (16-bit) | Process-to-process delivery |
| Network | IP (v4/v6) | Datagram / Packet | IP addresses (32/128-bit) | Host-to-host, connectionless, best-effort |
| Link | Ethernet, WiFiโฆ | Frame | MAC addresses (48-bit) | Node-to-node on same link |
| Feature | TCP | UDP |
|---|---|---|
| Connection | Connection-oriented (3-way handshake) | Connectionless |
| Reliability | Reliable (ACK + retransmit) | Unreliable (best effort) |
| Ordering | In-order delivery guaranteed | No ordering |
| Data Model | Byte stream (no boundaries) | Datagrams (boundaries preserved) |
| Header size | 20+ bytes | 8 bytes |
| Speed | Slower (overhead of reliability) | Faster (less overhead) |
| Flow control | Yes (sliding window) | No |
| Congestion control | Yes (slow start, AIMD) | No |
| Broadcast/Multicast | No (unicast only) | Yes |
| Socket type | SOCK_STREAM | SOCK_DGRAM |
| Use cases | HTTP, SSH, FTP, email, databases | DNS, video call, gaming, DHCP, NTP |
| Function | Who Calls It | Purpose | Returns |
|---|---|---|---|
socket(domain, type, proto) |
Both | Create socket | fd or -1 |
setsockopt(fd, level, opt, val, len) |
Both (server usually) | Set socket options | 0 or -1 |
bind(fd, addr, addrlen) |
Server (UDP: both) | Assign local address | 0 or -1 |
listen(fd, backlog) |
TCP Server only | Mark as passive | 0 or -1 |
accept(fd, addr, addrlen) |
TCP Server only | Wait for client, get new fd | new fd or -1 |
connect(fd, addr, addrlen) |
Client | Connect to server | 0 or -1 |
send(fd, buf, len, flags) |
Both (TCP) | Send data | bytes sent or -1 |
recv(fd, buf, len, flags) |
Both (TCP) | Receive data | bytes or 0 (closed) or -1 |
sendto(fd, buf, len, flags, addr, al) |
Both (UDP) | Send UDP datagram | bytes sent or -1 |
recvfrom(fd, buf, len, flags, addr, al) |
Both (UDP) | Receive UDP datagram | bytes or -1 |
close(fd) |
Both | Close socket (sends FIN for TCP) | 0 or -1 |
shutdown(fd, how) |
Both | Partial close (SHUT_RD/WR/RDWR) | 0 or -1 |
inet_pton(af, str, dst) |
Both | String IP โ binary | 1 ok, 0 bad str, -1 err |
inet_ntop(af, src, str, size) |
Both | Binary IP โ string | str pointer or NULL |
htons() / htonl() |
Sender | Host โ Network byte order | converted value |
ntohs() / ntohl() |
Receiver | Network โ Host byte order | converted value |
| Feature | IPv4 | IPv6 |
|---|---|---|
| Address size | 32 bits | 128 bits |
| Notation | 192.168.1.1 (dotted decimal) | 2001:db8::1 (colon hex) |
| Capacity | ~4.3 billion | 3.4 ร 10ยณโธ |
| Header size | 20 bytes (variable) | 40 bytes (fixed) |
| Checksum | Yes (in IP header) | No (handled by transport layer) |
| Fragmentation | Routers can fragment | Only sender fragments |
| Loopback | 127.0.0.1 | ::1 |
| All interfaces | 0.0.0.0 (INADDR_ANY) | :: (in6addr_any) |
| Socket struct | sockaddr_in | sockaddr_in6 |
| Address family | AF_INET | AF_INET6 |
| strlen constant | INET_ADDRSTRLEN = 16 | INET6_ADDRSTRLEN = 46 |
| State | Who | Meaning |
|---|---|---|
| LISTEN | Server | Waiting for incoming connections (after listen()) |
| SYN_SENT | Client | SYN sent, waiting for SYN-ACK from server |
| SYN_RECEIVED | Server | SYN received, SYN-ACK sent, waiting for ACK |
| ESTABLISHED | Both | Connection open, data flows in both directions |
| FIN_WAIT_1 | Active closer | FIN sent, waiting for ACK or FIN |
| FIN_WAIT_2 | Active closer | FIN ACK’d, waiting for peer’s FIN |
| CLOSE_WAIT | Passive closer | FIN received, app should close soon |
| LAST_ACK | Passive closer | FIN sent, waiting for final ACK |
| TIME_WAIT | Active closer | Final ACK sent, waiting 2รMSL before truly closing |
| CLOSED | Both | No connection. Initial and final state. |
/* Check TCP states on Linux: */
$ ss -tn
$ netstat -tn /* older systems */
/* Look for TIME_WAIT, ESTABLISHED, LISTEN states */
Covers all 8 parts โ organized by topic for quick review
Q: Name the 4 layers of the TCP/IP model and their roles.
A: (1) Link layer โ moves frames on local network, uses MAC addresses. (2) Network/Internet layer โ routes packets across networks, uses IP addresses. (3) Transport layer โ end-to-end process communication, uses port numbers. (4) Application layer โ your programs (HTTP, DNS, SSH).
Q: What is the difference between a hub, switch, and router?
A: Hub (Layer 1) โ broadcasts all frames to all ports, no intelligence. Switch (Layer 2) โ forwards frames based on MAC addresses, learns which device is on which port. Router (Layer 3) โ forwards IP packets between different networks based on IP addresses and routing tables. Sockets and TCP/IP operate at and above the router level.
Q: What is ARP and why is it needed?
A: ARP (Address Resolution Protocol) maps IP addresses to MAC addresses on a local network. When your machine wants to send to 192.168.1.5 (known IP), it broadcasts an ARP request asking “who has 192.168.1.5?” The owner replies with its MAC address. Without ARP, IP packets cannot be wrapped in Ethernet frames for local delivery. ARP operates between the Network and Link layers.
Q: Why is IP called “connectionless and unreliable”?
A: Connectionless โ no setup before sending; each datagram is independent; datagrams may take different routes. Unreliable โ no guarantee of delivery, ordering, or deduplication. IP makes no effort to recover lost packets. It is a “best-effort” delivery service. Reliability must be added by a higher layer (TCP) or the application itself.
Q: What is CIDR notation and what does /24 mean?
A: CIDR (Classless Inter-Domain Routing) uses a suffix /N to indicate how many bits are the network part. 192.168.1.0/24 means 24 bits are the network (192.168.1) and 8 bits are the host (0โ255). This gives 256 total addresses, 254 usable hosts. /8 = class A (16M hosts), /16 = class B (65K hosts), /24 = class C (254 hosts).
Q: What is Path MTU Discovery?
A: PMTUD finds the smallest MTU along the entire path from source to destination. The sender sets the DF (Don’t Fragment) flag and sends increasingly large packets. If a router can’t forward it (packet exceeds link MTU), it drops the packet and sends an ICMP “Fragmentation Needed” message back with the allowed MTU. The sender then knows to use a smaller size. TCP uses PMTUD automatically to set the MSS (Maximum Segment Size).
Q: What is the difference between close() and shutdown() on a TCP socket?
A: close(fd) decrements the fd’s reference count. When it hits 0, it shuts down both directions (sends FIN) and releases the fd. If you have duplicated the fd (via dup/fork), other copies still work. shutdown(fd, how) immediately shuts down one or both directions: SHUT_RD (stop receiving), SHUT_WR (send FIN, stop sending), SHUT_RDWR (both). Doesn’t close the fd. Useful for half-close scenarios โ e.g., send data then signal “no more” with SHUT_WR while still receiving the response.
Q: What is Nagle’s algorithm and when would you disable it?
A: Nagle’s algorithm coalesces small TCP segments โ it holds small writes until the previous segment is acknowledged or enough data accumulates (MSS bytes). Reduces the number of tiny packets (improves throughput on slow links). Disable it (TCP_NODELAY option) when you need low latency and send small messages frequently โ e.g., SSH interactive sessions, gaming, financial trading systems. Use setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)).
Q: What is a SYN flood attack and how is SYN cookies a defense?
A: SYN flood โ attacker sends many SYN packets with spoofed source IPs. Server allocates resources for each half-open connection (SYN_RECEIVED state) until the SYN queue fills up, preventing legitimate connections. SYN cookies defense: instead of storing state for half-open connections, the server encodes connection info into the ISN (sequence number) it sends back. Only when the ACK arrives and the cookie validates does the server allocate real resources. The SYN queue is no longer a bottleneck. Enable: echo 1 > /proc/sys/net/ipv4/tcp_syncookies.
Q: What is TCP keepalive and when is it useful?
A: TCP keepalive periodically sends small probes on idle connections to detect if the other side has crashed or become unreachable (without sending FIN/RST). Without keepalive, a dead connection is never detected โ your socket appears open but data is never received. Enable: setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)). Tune intervals: TCP_KEEPIDLE (idle time before first probe), TCP_KEEPINTVL (probe interval), TCP_KEEPCNT (number of probes before giving up).
Q: How do you make a socket non-blocking? Why?
A: Two ways: (1) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) or (2) socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0) (Linux). Non-blocking mode: accept(), connect(), recv(), send() return immediately with EAGAIN/EWOULDBLOCK if they would block. Used with I/O multiplexing (select, poll, epoll) to handle many connections in a single thread without blocking. This is the basis of high-performance servers (nginx, Node.js).
Q: What is the difference between select(), poll(), and epoll()?
A: All three are I/O multiplexing โ wait for one of many fds to become ready. select() โ oldest; limited to 1024 fds; copies fd_set on each call; O(n) scan. poll() โ no fd limit; still copies event array on each call; O(n) scan. epoll() โ Linux-specific; scalable; kernel maintains the watched set; only returns ready fds; O(1) for add/remove; O(events) for wait. Use epoll for high-performance Linux servers.
Q: What does getsockname() return and when do you use it?
A: getsockname(fd, addr, addrlen) returns the local address (IP + port) bound to a socket. Useful when you call bind() with port 0 (OS assigns ephemeral port) and need to know which port was actually assigned. Also useful on the client to find out which ephemeral port was assigned after connect().
Q: How do you write a server that handles both IPv4 and IPv6?
A: Use AF_INET6 with the IPV6_V6ONLY option set to 0 โ on most Linux systems, an IPv6 socket can also accept IPv4 connections (via IPv4-mapped IPv6 addresses like ::ffff:192.168.1.1). Alternatively, create two listening sockets โ one AF_INET and one AF_INET6 โ and use poll/epoll to watch both. Use struct sockaddr_storage in accept() to hold either address type.
โ Forgetting htons() on port
Port number goes in wrong byte order. Server listens on wrong port. Fix: always call htons() before assigning to sin_port.
โ Assuming recv() returns all data
TCP is a stream. recv() may return partial data. Always loop until you have all bytes expected.
โ Not checking recv() return value
recv() returns 0 when peer closes connection, -1 on error. Not checking this causes infinite loops or crashes.
โ Forgetting SO_REUSEADDR
Server restart fails with “Address already in use” because port is in TIME_WAIT. Add setsockopt SO_REUSEADDR before bind.
โ Using memset() with wrong size
Not zeroing sockaddr_in before use leaves garbage in sin_zero padding. Always: memset(&addr, 0, sizeof(addr)).
โ Not closing accepted socket
Each accepted connection uses a file descriptor. If you don’t close(connfd), you leak fds and eventually hit the per-process fd limit.
OSI vs TCP/IP model, encapsulation, PDUs, routing
IP header, addressing, fragmentation, MTU, CIDR, inet_pton
UDP header, SOCK_DGRAM, sendto/recvfrom, use cases, complete UDP echo server
3-way handshake, connection termination, reliability, flow control, congestion control, byte stream
Port ranges, well-known ports, sockaddr_in/in6/storage, 5-tuple, socket pairs
Big endian vs little endian, htons/htonl/ntohs/ntohl, endianness detection
socket/bind/listen/accept/connect, SO_REUSEADDR, complete TCP echo server
Quick reference tables, TCP vs UDP comparison, state machine, common mistakes, full Q&A bank
