Introduction

An application reaches TCP and UDP through the operating system's socket interface, which first appeared in Berkeley UNIX and is now on nearly every system. A socket is an endpoint, named by a file descriptor, through which a process sends and receives data. The calls are system calls: the transport protocol itself runs in the kernel, so connect starts a three-way handshake, send copies bytes into the kernel's send buffer, and close eventually sends a FIN.

The essentials are which calls a client and a server make and in what order, which calls block, what accept returns, how TCP and UDP sockets differ, and how many sockets exist when a server has several clients. All of these follow from the transport layer underneath (Transport Layer: UDP and TCP Basics).

Prerequisites

Core concepts

The calls

CallWhoWhat it does
socket(domain, type, protocol)BothCreate an endpoint; SOCK_STREAM for TCP, SOCK_DGRAM for UDP. Returns a descriptor
bind(s, addr)Server (client optional)Attach a local IP address and port
listen(s, backlog)TCP serverMark the socket passive; the kernel queues up to backlog connections
accept(s)TCP serverTake a completed connection from the queue; returns a new socket for it (blocks if none)
connect(s, addr)TCP clientRun the three-way handshake to addr (blocks until done or refused); binds an ephemeral port if none was bound
send / write, recv / readConnected socketsMove bytes to or from the kernel buffers
sendto, recvfromUDPSend to, or receive with, an explicit peer address per datagram
shutdown(s, how)BothClose one direction (for example stop sending: FIN) while still receiving
close(s)BothRelease the descriptor; for TCP, start connection release

Call sequence for TCP

Text
SERVER                                  CLIENT
s = socket(STREAM)                      
bind(s, port 80)
listen(s, backlog)
c = accept(s)       ... blocks ...      t = socket(STREAM)
                    <-- SYN ----------- connect(t, server:80)   (blocks)
                    --- SYN+ACK ------>
                    <-- ACK ----------- connect returns
accept returns c
recv(c)             <-- data ---------- send(t, request)
send(c, reply)      --- data --------->  recv(t)
close(c)            --- FIN ---------->  recv(t) returns 0 (end of stream)
                    <-- FIN ----------- close(t)

The handshake is done by the kernels: connect returns, and the connection waits in the listening socket's queue, even before the server calls accept. accept only hands over a connection that is already established.

Call sequence for UDP

Server: socket(DGRAM), bind(port), then a loop of recvfrom and sendto. Client: socket(DGRAM), then sendto and recvfrom. There is no listen, accept or handshake. A UDP socket may call connect, but that only records a default peer (so plain send and recv work and datagrams from other sources are filtered); nothing is sent on the network.

Two columns of boxes connected by arrows, server on the left and client on the right. Server column: socket, bind (port 80), listen, accept (blocks). Client column: socket, connect. Between the columns, three arrows for the handshake: SYN from client to server, SYN+ACK back, ACK forward; connect returns after the third, and accept returns a new socket. Then send on the client and recv on the server with a request arrow, send on the server and recv on the client with a reply arrow, close on the server sending FIN and recv on the client returning 0, and close on the client sending FIN back. A side note shows the listening socket staying open while accept returns a separate connected socket.
Figure 1. TCP socket calls: the server runs socket, bind, listen and accept; the client's connect drives the handshake; accept returns a new connected socket, and recv returns 0 after the peer's FIN.

Two sockets on the server

The listening socket stays bound to the server port and only produces connections. Each accept returns a connected socket identified by the full 4-tuple (server IP, server port, client IP, client port). All connected sockets share the server's local port; they differ in the client's address or port. A server with nn open client connections therefore holds n+1n + 1 TCP sockets on that port.

Blocking

CallBlocks until
acceptA completed connection is in the queue
connect (TCP)The handshake completes, or fails (RST: connection refused; no reply: timeout)
recv / readAt least one byte is available, or the peer has closed (returns 0)
send / writeThere is room in the kernel send buffer (not until the peer receives it)
recvfrom (UDP)A datagram arrives

Non-blocking mode and select or poll let one thread wait on many sockets at once.

Mathematical explanation: stream semantics

TCP is a byte stream, so the boundaries between send calls are not preserved: two sends of 3 bytes may arrive as one recv of 6 bytes, or one send of 6 bytes as two recv calls. A receiver that expects LL bytes must loop until it has LL. UDP keeps boundaries: each recvfrom returns exactly one datagram (truncated if the buffer is too small).

If send returns n>0n>0, the kernel accepted those nn bytes, not necessarily all LL requested bytes; loop over the remainder when n<Ln<L. This still does not mean the peer has received them; delivery is confirmed only by TCP's ACKs, which the application does not see.

Worked examples

Example 1: order of calls

Which sequence is a correct TCP server? socket, bind, listen, accept, recv, send, close. The client side needs only socket, connect, send, recv, close; bind is optional because connect assigns an ephemeral port. Calling accept without listen, or listen on a UDP socket, fails.

Example 2: counting sockets

A web server has 3 clients connected. On the server: 1 listening socket + 3 connected sockets = 4, all with local port 80. On each client: 1 socket with its own ephemeral port. The 3 server-side connected sockets are distinguished by the clients' (IP, port) pairs.

Example 3: what recv returns

The client sends "abc" and then "def" on a TCP connection and closes it. The server's first recv(100) may return "abcdef" (or "abc"), and once all data is read, recv returns 0 bytes: the end-of-stream signal caused by the client's FIN. Over UDP, the same two sendto calls give two recvfrom results, "abc" and "def".

Example 4: no server

A client calls connect to a port where nothing is listening. The server's TCP replies to the SYN with RST, and connect fails with "connection refused". For UDP, sendto to such a port succeeds locally; the error, if any, comes back later as an ICMP port-unreachable message.

Example 5: restarting a server during TIME-WAIT

A server that closes its connections first (an active close) leaves them in TIME-WAIT on its own port. If it is restarted at once, the new listening socket's bind to that port fails on Linux with "address already in use" (EADDRINUSE) until TIME-WAIT ends; a server that sets SO_REUSEADDR on its listening socket before every bind can restart at once; on Linux the option must have been set on the earlier socket too. The transport's TIME-WAIT state is visible to the program through the socket API.

An iterative server handles one connection at a time: accept, serve, close, accept again. A concurrent server can fork a process or dispatch a thread after each accept. Fork case: the child serves the connected socket and closes its inherited listening descriptor; the parent closes its copy of the connected descriptor and returns to accept. Each process closes only the copies it does not use. Thread case: threads share one descriptor table, so the worker must not close the shared listening socket and the acceptor must not close the connection assigned to the worker; the worker closes that connection when finished (Inter-Process Communication, System Calls and OS Structure).

Important properties and observations

  • A socket is a file descriptor; read, write and close work on it.
  • Only the server binds a well-known port; clients normally let connect or the first sendto choose one.
  • listen does not block; accept does.
  • close is not immediate release: the kernel still sends queued data and the FIN, and the side that closed first sits in TIME-WAIT.
  • shutdown gives a half-close: stop sending (the peer reads end of stream) but keep receiving.

Common misconceptions.

  • "accept performs the handshake." The kernel does; accept returns an established connection.
  • "accept returns the listening socket." It returns a new socket; the listening one keeps listening.
  • "Each send matches one recv in TCP." Only in UDP.
  • "UDP connect contacts the server." It only fixes a default peer locally.
  • "The client must call bind." connect binds automatically.

GATE examination perspective

  • Server order: socket, bind, listen, accept; client: socket, connect.
  • Blocking calls: accept, connect, recv, recvfrom (and send when the buffer is full).
  • Sockets on a server with nn clients: n+1n + 1, sharing the local port.
  • TCP versus UDP calls: no listen or accept for UDP; sendto and recvfrom carry addresses.
  • recv returning 0 means the peer has closed its sending side.

Summary

Sources

  1. A. S. Tanenbaum, D. J. Wetherall, Computer Networks, 5th ed., Pearson, 2011: Sections 6.1.3 (Berkeley Sockets) and 6.1.4 (a socket programming example).
  2. J. F. Kurose, K. W. Ross, Computer Networking: A Top-Down Approach, 8th ed., Pearson, 2021: Sections 2.7.1 (Socket Programming with UDP) and 2.7.2 (Socket Programming with TCP).
  3. B. A. Forouzan, Data Communications and Networking, 5th ed., McGraw-Hill, 2013: Chapter 25 (Introduction to Application Layer).

Next steps