Socket

On this page 8

A socket is an operating system endpoint through which an application sends and receives data over a network, identified by a transport protocol, an IP address and a port number. In networking and in the study of transport protocols, the socket is the boundary where application code hands bytes or datagrams to the kernel, which then applies the rules of TCP or UDP on the wire.

The term covers two related ideas. The socket address is the combination of IP address and port, while the socket object is the kernel structure, exposed to programs through the Berkeley sockets API, that holds buffers, state and options for one communication endpoint.

How a socket connects an application to the network

A socket works as a file-like handle that the kernel returns when an application calls socket(). On Unix-like systems it is a file descriptor, and on Windows it is a handle managed by Winsock. The application reads and writes through this handle, while the kernel performs segmentation, retransmission, checksums and routing.

Each socket is created with an address family, such as AF_INET for IPv4 or AF_INET6 for IPv6, and a socket type, such as SOCK_STREAM for TCP or SOCK_DGRAM for UDP. The kernel stores a send buffer and a receive buffer for every socket, so the application and the network can work at different speeds.

A server and a client follow different call sequences. The following table shows the typical lifecycle of a TCP socket on each side.

CallSideWhat it does
socket()BothCreates the endpoint and returns a descriptor
bind()Server, optional on clientAssigns a local IP address and port
listen()ServerMarks the socket as passive and sets the backlog queue
connect()ClientStarts the TCP handshake toward a remote address
accept()ServerReturns a new socket for one established connection
send() / recv()BothMoves data through the kernel buffers
close() / shutdown()BothEnds the connection and releases resources
Main calls in the TCP socket lifecycle

The five-tuple and connection identity

A connected TCP socket is uniquely identified by the five-tuple: protocol, local IP address, local port, remote IP address and remote port. This is why a web server can keep thousands of connections on port 443 at the same time: every accepted socket shares the local address and port but differs in the remote part.

The listening socket and the connected sockets are separate objects. The listening socket only accepts new connections from the backlog queue, while each call to accept() creates a new socket dedicated to one client. Closing the listening socket stops new connections but does not break the established ones.

On the client side, the kernel usually picks the local port automatically from the ephemeral port range. On Linux the default range is 32768 to 60999, while Windows and the IANA recommendation use 49152 to 65535. A host that opens many short outbound connections to one destination can exhaust this range, which leads to connection failures under load.

Socket types and their transport behavior

The socket type determines which transport semantics the application receives. Stream sockets deliver an ordered byte stream without message boundaries, while datagram sockets preserve message boundaries but guarantee neither delivery nor order.

Socket typeTypical protocolDelivery modelTypical use
Stream socketTCPReliable, ordered byte streamWeb, mail, databases, SSH
Datagram socketUDPIndependent messages, no guaranteesDNS, VoIP, games, QUIC
Raw socketIP or ICMP directlyPackets with headers under program controlPing, traceroute, packet tools
Unix domain socketLocal kernel transportStream or datagram on one hostDatabase and proxy connections on the same machine
Sequenced packet socketSCTPReliable messages with boundariesTelecom signaling
Common socket types compared

A frequent misunderstanding is that one send() call on a TCP socket matches one recv() call on the other side. TCP is a byte stream without message boundaries, so the receiver may get one message split across several reads or several messages in a single read. Applications must therefore add their own framing, such as a length prefix or a delimiter.

Socket, port and connection compared

Socket, port number and connection are related but not interchangeable terms. A port is only a 16-bit number in the transport header, whereas a socket is the full endpoint and the kernel object behind it.

TermWhat it isScope
Port number16-bit identifier from 0 to 65535Part of the transport header
Socket addressIP address plus portOne endpoint on one host
SocketKernel object with buffers, state and optionsOne endpoint as seen by an application
ConnectionPair of connected TCP socketsBoth endpoints and their shared state
TCP handshakeSYN, SYN-ACK, ACK exchangeThe setup step that creates a connection
How the socket relates to neighboring terms

Important socket options and tuning

Socket behavior is adjusted with setsockopt(), and a few options account for most practical tuning. They control buffer sizes, address reuse, latency and timeouts.

OptionEffectWhen to set it
SO_REUSEADDRAllows binding while old connections sit in TIME_WAITServers that restart quickly
SO_REUSEPORTLets several sockets share one port for load distributionMulti-process servers on Linux
TCP_NODELAYDisables the Nagle algorithmInteractive, latency-sensitive traffic
SO_RCVBUF / SO_SNDBUFSets receive and send buffer sizesHigh-bandwidth, high-latency links
SO_KEEPALIVESends probes on idle connectionsDetecting dead peers behind NAT
SO_LINGERControls behavior of close() with unsent dataRarely; forced resets
Frequently used socket options

Buffer size matters most on long, fast paths. To fill a link, the buffer must hold at least the bandwidth-delay product: a 1 Gbit/s path with 50 ms round-trip time needs about 6 MB of window. Modern kernels use automatic buffer tuning, so manual values can actually limit throughput if they are set too low.

Common socket problems and their causes

Most socket failures in production come from resource limits, timeouts and connection state, not from the network itself. Recognizing the error code usually points directly to the cause.

  • Address already in use means another socket holds the port, or old connections remain in TIME_WAIT without SO_REUSEADDR.
  • Connection refused means the destination host answered with a reset because nothing listens on that port.
  • Too many open files means the process reached its file descriptor limit, which sockets count against.
  • Many sockets in TIME_WAIT indicate a large number of short connections; connection reuse fixes the cause better than kernel tweaks.
  • Many sockets in CLOSE_WAIT indicate an application bug: the peer closed, but the local program never called close().

Tools such as ss and netstat list every socket with its state, addresses and queue sizes. A growing receive queue shows that the application reads too slowly, while a growing send queue usually points to a slow network path or receiver.

A non-technical view

A socket is like a phone line plugged into a program. The computer has an address, and each program that wants to talk over the network gets its own numbered line on that address. The socket is the line itself, together with the small waiting rooms where incoming and outgoing data sit until someone handles them.

When a browser opens a website, it asks the computer for a new socket, dials the server, and then simply writes and reads through it. The operating system handles the hard parts, such as resending lost pieces and putting data back in the right order.

A concrete example

An online store runs its web server on a Linux machine with one listening socket on port 443. During a seasonal sale, monitoring shows about 20,000 established connections, each one a separate socket with a different client address and port. The server handles them with an event loop that watches all sockets through epoll.

The operations team then notices errors from the application to its database: the application opens a new TCP connection for every query, and tens of thousands of client sockets pile up in TIME_WAIT until ephemeral ports run out. The fix is a connection pool of 50 persistent sockets, which removes the port exhaustion and also cuts query latency because no new handshake is needed for each request.