G27
Self-checkedTier 1 11 min readcn.socket-api

Socket API

How a program uses the network: the socket as a file-descriptor-like handle, the TCP server sequence socket - bind - listen - accept - recv/send - close and the client sequence socket - connect - send/recv - close, what bind, listen and accept really do (the handshake is completed by the kernel before accept, accept returns a new socket), why a TCP recv is not matched to a send (a byte stream has no message boundaries) while a UDP datagram is delivered as a unit, ports and the address-in-use error, and the TCP states seen from outside; the C programs on the page were compiled and run, and the TCP states come from a real conversation observed with netstat.

Why it exists

An application on one computer must talk to an application on another, but the transport protocols live inside the operating system. The socket API (from the Berkeley UNIX of the early 1980s) is the interface through which programs ask the kernel for network communication: you create a socket, bind it to an address and port, connect or accept, and then send and receive almost as if you were writing to and reading from a file. It sits between the application layer and the transport layer (layering) and is implemented with system calls (system calls).

Prerequisites

You need TCP's connection and byte stream (TCP basics) and the idea of a system call (system calls).

Precise definitions

A socket is an endpoint of communication. A program creates one with socket(domain, type, protocol) and gets back a small integer, a descriptor, like a file descriptor. The type selects the transport service: SOCK_STREAM is TCP (reliable byte stream), SOCK_DGRAM is UDP (unreliable datagrams). The domain AF_INET means IPv4.

An endpoint address is the pair (IP address, port number) (struct sockaddr_in: family, 16-bit port in network byte order, 32-bit address).

The TCP server sequence (typical):

callwhat it does
socket()creates the socket
bind(s, addr)assigns the local address and port (port 0: let the system pick a free one)
listen(s, backlog)turns the socket into a listening socket; the kernel will complete handshakes for it and queue up to about backlog established connections
accept(s)takes the next established connection from the queue (blocking if there is none) and returns a new socket for that connection together with the client's address
recv(), send() (or read, write)transfer data on the new socket
close()closes a socket; the other side's recv then returns 00 (end of stream)

The TCP client sequence: socket(), connect(s, server address) (the kernel sends the SYN and returns when the handshake is complete or fails), then send()/recv(), then close(). The client normally does not call bind: the system chooses a free ephemeral port as the local port at connect.

The UDP sequence: socket(AF_INET, SOCK_DGRAM, 0); the receiver binds to a port; sendto(s, data, destination) and recvfrom(s, buf, ...). There is no listen, no accept, no connect and no handshake.

Two kinds of socket in a TCP server. The listening socket stays bound to the server's well-known port and only accepts connections. Each accepted connection has its own connected socket (a new descriptor) with the same local port and the client's address as the remote end. Connections are told apart by the four-tuple (source IP, source port, destination IP, destination port), so many clients can use one server port.

How it works

A TCP conversation, seen from the kernel

A real TCP conversation on the loopback interface: start

Computed by a script, not typed
stepserver callsclient callsTCP states observed with netstat
step 1
step 2
step 3
step 4
step 5
step 6

Step 0

A Python server and client talk over 127.0.0.1; after every step the TCP states are read with the system's netstat. The states are OBSERVED (macOS netstat), not assumed.

0 / 6
computed or observed by script: real loopback sockets (netstat states), a real HTTP server, the DNS encoder, exact timing formulas. python3 scripts/gen-cn5-traces.py

The table was produced by a real server and client on the loopback interface, reading the states of the TCP sockets with netstat after each step. Note that after connect() the connection is already ESTABLISHED although the server has not yet called accept(): the three-way handshake is handled by the kernel, and accept() merely hands the finished connection to the program. After the client closes, the client socket waits in FIN_WAIT_2 and the server's in CLOSE_WAIT until the server closes; the socket of the side that closed first ends in TIME_WAIT.

The C program

The program below does both the server and the client side in one process (possible because the connection is completed by the kernel before accept): it creates a listening socket on a port chosen by the system, connects to it, sends two pieces of data of 22 and 33 bytes, accepts, and receives them with a single call asking for 55 bytes.

#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
 
int main(void) {
    /* server side: socket, bind (port 0 = let the system choose), listen */
    int ls = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in a;
    memset(&a, 0, sizeof a);
    a.sin_family = AF_INET;
    a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    a.sin_port = 0;
    if (bind(ls, (struct sockaddr *)&a, sizeof a) < 0) return 1;
    if (listen(ls, 1) < 0) return 1;
    socklen_t len = sizeof a;
    getsockname(ls, (struct sockaddr *)&a, &len);
 
    /* client side: socket, connect; the handshake finishes in the kernel before accept is called */
    int c = socket(AF_INET, SOCK_STREAM, 0);
    int one = 1;
    setsockopt(c, IPPROTO_TCP, TCP_NODELAY, &one, sizeof one);
    if (connect(c, (struct sockaddr *)&a, sizeof a) < 0) return 1;
    send(c, "ab", 2, 0);
    send(c, "cde", 3, 0);
 
    int s = accept(ls, NULL, NULL);
    char buf[100];
    ssize_t n = recv(s, buf, 5, MSG_WAITALL); /* wait until 5 bytes have arrived */
    printf("two send calls (2 + 3 bytes), one recv for 5 bytes returned %zd bytes: %.*s\n", n, (int)n, buf);
 
    struct sockaddr_in cl, peer, srv;
    len = sizeof cl;
    getsockname(c, (struct sockaddr *)&cl, &len);
    len = sizeof peer;
    getpeername(s, (struct sockaddr *)&peer, &len);
    len = sizeof srv;
    getsockname(s, (struct sockaddr *)&srv, &len);
    printf("accepted socket's peer port == client's own port: %s\n", peer.sin_port == cl.sin_port ? "yes" : "no");
    printf("accepted socket's local port == listening port: %s\n", srv.sin_port == a.sin_port ? "yes" : "no");
    printf("accepted socket is a new descriptor: %s\n", s != ls ? "yes" : "no");
 
    /* a second bind to the port that is in use fails */
    int t = socket(AF_INET, SOCK_STREAM, 0);
    if (bind(t, (struct sockaddr *)&a, sizeof a) < 0) printf("second bind to the same port fails: %s\n", strerror(errno));
    close(t);
 
    /* closing one side: the other side's recv returns 0 (end of the stream) */
    close(c);
    n = recv(s, buf, sizeof buf, 0);
    printf("after the client closed, recv returned %zd\n", n);
    close(s);
    close(ls);
    return 0;
}
two send calls (2 + 3 bytes), one recv for 5 bytes returned 5 bytes: abcde
accepted socket's peer port == client's own port: yes
accepted socket's local port == listening port: yes
accepted socket is a new descriptor: yes
second bind to the same port fails: Address already in use
after the client closed, recv returned 0

The first line shows that TCP has no message boundaries: the two send calls were joined in the byte stream and one recv (with MSG_WAITALL, which waits for all 55 bytes) returned both. Without MSG_WAITALL a recv returns whatever bytes are available at that moment: in an earlier trial one call returned only the first 22 bytes and the next call the other 33. A TCP program must therefore loop until it has read a complete message and must mark message ends itself (a length field, a delimiter, or closing the connection). The next lines show that the accepted socket is a new descriptor with the same local port as the listening socket, and that its remote port is the client's ephemeral port. A second bind to a port in use fails with the error "Address already in use". After the client closes, recv returns 00.

UDP keeps the boundaries

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
 
int main(void) {
    int r = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in a;
    memset(&a, 0, sizeof a);
    a.sin_family = AF_INET;
    a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    a.sin_port = 0;
    if (bind(r, (struct sockaddr *)&a, sizeof a) < 0) return 1;
    socklen_t len = sizeof a;
    getsockname(r, (struct sockaddr *)&a, &len);
 
    int s = socket(AF_INET, SOCK_DGRAM, 0); /* no connect, no handshake */
    sendto(s, "ab", 2, 0, (struct sockaddr *)&a, sizeof a);
    sendto(s, "cde", 3, 0, (struct sockaddr *)&a, sizeof a);
 
    char buf[100];
    for (int i = 1; i <= 2; i++) {
        ssize_t n = recvfrom(r, buf, sizeof buf, 0, NULL, NULL);
        printf("recvfrom %d returned %zd bytes: %.*s\n", i, n, (int)n, buf);
    }
    close(s);
    close(r);
    return 0;
}
recvfrom 1 returned 2 bytes: ab
recvfrom 2 returned 3 bytes: cde

Each recvfrom returns exactly one datagram: the application sees the messages as they were sent (the two calls to sendto give two calls to recvfrom with 22 and 33 bytes). If the buffer is smaller than the datagram the excess is discarded. UDP does not guarantee delivery or order (on the loopback interface they are in practice never lost).

TCP (SOCK_STREAM)UDP (SOCK_DGRAM)
set-uplisten / accept / connect (handshake)none
databyte stream, no message boundariesdatagrams with boundaries
reliabilityreliable, orderednone
sender and receiverone connection per pair of socketsone socket can talk to many peers
receiver callrecvrecvfrom

Worked examples

EX 1Order of the calls

Easy

TCP server: socket, bind, listen, accept, recv/send, close. TCP client: socket, connect, send/recv, close. A UDP server: socket, bind, recvfrom/sendto.

EX 2How many sockets does the server have?

Medium

A server listening on port 8080 with 33 clients connected has 44 sockets: one listening socket and three connected sockets. All connected sockets have local port 8080; they differ in the remote address and port.

EX 3Reading until a message is complete

Medium

A client sends a 10001000-byte message with two send calls. The server's first recv may return 300300 bytes, the next 700700 (or 10001000 at once). The server must call recv repeatedly, adding up the counts, until 10001000 bytes (known from a length header) have arrived. For UDP a message of 10001000 bytes sent with one sendto is returned by one recvfrom.

EX 4Typical questions

GATE level

(a) "Which call blocks until a client connects?" accept. (b) "Which call does a UDP server not need?" listen and accept. (c) "What does accept return?" A new socket descriptor for the connection. (d) "Does the client have to call bind?" No, the system assigns an ephemeral port. (e) "What does recv return when the peer has closed?" 00. (f) "Which socket type for a reliable stream?" SOCK_STREAM. (g) "How can many clients be served on one port?" Each connection has its own socket, identified by the four-tuple.

Cheat box

Cheat box

  • TCP server: socket, bind, listen, accept (new socket), recv/send, close. Client: socket, connect, send/recv, close.
  • UDP: socket, bind, recvfrom/sendto; no connection.
  • accept returns a NEW socket; the listening socket stays; same local port, different peer.
  • TCP is a byte stream (loop on recv); UDP keeps datagram boundaries.
  • The kernel completes the handshake before accept; recv returning 00 means the peer closed.

Traps and GATE patterns

Connections

The socket calls are system calls into the kernel's TCP and UDP code (system calls); what happens inside connect and close is the handshake and teardown of TCP basics. The application protocols that use sockets are HTTP over TCP and DNS over UDP.

PYQs

7 previous year questions from your book. I re-solved each one myself (1 by running or simulating, 6 by reasoning only); the book's key is shown next to my answer. All PYQs

year not read yetQ33 · page 553 of the book
A TCP server application is programmed to listen
on port number P on host S. A TCP client is
connected to the TCP server over the network.
Consider that while the TCP connection was active,
the server machine S crashed and rebooted.
Assume that the client does not use the TCP
keepalive timer.

Which of the following behaviors is/are possible?
  • (a)If the client sends a packet after the server reboot, it will receive a FIN segment.
  • (b)If the client was waiting to receive a packet, it may wait indefinitely.
  • (c)The TCP server application on S can listen on P after reboot.
  • (d)If the client sends a packet after the server reboot, it will receive a RST segment.
GATE 2017 · MCQQ48 · page 555 of the book
Consider socket API on a Linux machine that
supports connected UDP sockets. A connected UDP
socket is a UDP socket on which connect function has
already been called. Which of the following
statements is/are CORRECT?

I. A connected UDP socket can be used to
communicate with multiple peers simultaneously.
II. A process can successfully call connect function
again for an already connected UDP socket.
  • (a)I only
  • (b)II only
  • (c)Both I and II
  • (d)Neither I nor II
GATE 2015 · MCQQ58 · page 556 of the book
Identify the correct order in which a server process
must invoke the function calls accept, bind, listen, and
recv according to UNIX socket API.
  • (a)listen, accept, bind, recv
  • (b)bind, listen, accept, recv
  • (c)bind, accept, listen, recv
  • (d)accept, listen, bind, recv COMPUTER NETWORK
year not read yetQ66 · page 558 of the book
Which one of the following socket API functions
converts an unconnected active TCP socket into a
passive socket?
  • (a)connect
  • (b)bind
  • (c)listen
  • (d)accept
GATE 2008 · MCQ · 2 marksQ85 · page 562 of the book
A client process P needs to make a TCP connection
to a server process S. Consider the following
situation: the server process S executes a socket(),
a bind() and a listen() system call in that order,
following which it is preempted. Subsequently, the
client process P executes a socket() system call
followed by connect() system call to connect to the
server process S. The server process has not
executed any accept() system call. Which one of the
following events could take place?
  • (a)connect() system call returns successfully
  • (b)connect() system call blocks
  • (c)connect() system call returns an error
  • (d)connect() system call results in a core dump
GATE 2008 · MCQ · 1 markQ86 · page 562 of the book
Which of the following system calls results in the
sending of SYN packets?
  • (a)socket
  • (b)bind
  • (c)listen
  • (d)connect
GATE 2010 · MCQQ17 · page 579 of the book
Which one of the following is not a client-server
application?
  • (a)Internet chat
  • (b)Web browsing
  • (c)E-mail
  • (d)Ping

Self-check

Question 1

A server has accepted 55 connections and is still listening. How many sockets does it have?

Show answer

66: the listening socket plus five connected sockets.

Question 2

Why must a TCP receiver loop when reading a message?

Show answer

TCP is a byte stream without message boundaries; one recv can return only part of the data sent by one send (or the data of several sends).

Question 3

Which two calls are used by the UDP receiver instead of listen and accept?

Show answer

None are needed; it calls bind and then recvfrom.

Revision card

One-screen revision

  • TCP server: socket, bind, listen, accept, recv/send, close. Client: socket, connect, send/recv.
  • accept returns a new socket; handshake done by the kernel.
  • TCP: stream, loop on recv; UDP: datagrams, recvfrom, no connection.

References

  • ·Kurose, Ross, Computer Networking: A Top-Down Approach (8th edition), Chapter 2, Section 2.7 (Socket programming: creating network applications)
  • ·Stevens, Fenner, Rudoff, UNIX Network Programming, Volume 1 (3rd edition), Chapters 4 and 8 (Elementary TCP and UDP sockets)
  • ·Tanenbaum, Wetherall, Computer Networks (5th edition), Chapter 6, Section 6.1.3 (Berkeley sockets)

Verification

Both C programs on the page (a TCP exchange and a UDP exchange over the loopback interface, using port 0 so that the system chooses a free port) are compiled with -Wall -Wextra -Werror and run by npm run verify:c; the TCP program printed identical output in 40 consecutive runs on macOS (clang). The table of TCP states is OBSERVED: a Python server and client on 127.0.0.1 were examined with netstat after every step (scripts/gen-cn5-traces.py); the state names are those of this operating system and the sequence is the one of the textbooks. OBSERVATION worth knowing: in a first version of the TCP program the receiver called recv once without MSG_WAITALL and in 1 run of 5 got only 2 of the 5 bytes (and the other 3 on the next call): a single recv may return less than the sender sent, because the byte stream has no boundaries. The page therefore uses MSG_WAITALL for a deterministic demonstration. PORTABILITY: the programs use POSIX sockets (macOS, Linux); Windows uses Winsock with small differences. QUOTED, not verified here: the textbook statements about the backlog (the number of queued connections is system dependent), SO_REUSEADDR, blocking against non-blocking calls, select / poll, and the claim that the data of one UDP datagram cannot be split across recvfrom calls (the program shows datagram boundaries kept on loopback; a datagram larger than the buffer is truncated). Textbook chapter references are from memory. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (CRC remainders, binomial tail, checksums); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose). No defect found. Status raised to self-checked; verified needs a textbook or human check.

last verified: never

My notes (saved in this browser)