Chapter 56. Sockets: Introduction

Sockets are a method of IPC that allow data to be exchanged between applications, either on the same host (computer) or on different hosts connected by a network. The first widespread implementation of the sockets API appeared with 4.2BSD in 1983, and this API has been ported to virtually every UNIX implementation, as well as most other operating systems.

Note

The sockets API is formally specified in POSIX.1g, which was ratified in 2000 after spending about a decade as a draft standard. This standard has been superseded by SUSv3.

This chapter and the following chapters describe the use of sockets, as follows:

These chapters merely aim to give the reader a good grounding in the use of sockets. Sockets programming, especially for network communication, is an enormous topic in its own right, and forms the subject of entire books. Sources of further information are listed in Further Information.

In a typical client-server scenario, applications communicate using sockets as follows:

A socket is created using the socket() system call, which returns a file descriptor used to refer to the socket in subsequent system calls:

fd = socket(domain, type, protocol);

We describe socket domains and types in the following paragraphs. For all applications described in this book, protocol is always specified as 0.

Sockets exist in a communication domain, which determines:

Modern operating systems support at least the following domains:

Table 56-1 summarizes the characteristics of these socket domains.

Note

In some code, we may see constants with names such as PF_UNIX instead of AF_UNIX. In this context, AF stands for “address family” and PF stands for “protocol family.” Initially, it was conceived that a single protocol family might support multiple address families. In practice, no protocol family supporting multiple address families has ever been defined, and all existing implementations define the PF_ constants to be synonymous with the corresponding AF_ constants. (SUSv3 specifies the AF_ constants, but not the PF_ constants.) In this book, we always use the AF_ constants. Further information about the history of these constants can be found in Universality of I/O of [Stevens et al., 2004].

Every sockets implementation provides at least two types of sockets: stream and datagram. These socket types are supported in both the UNIX and the Internet domains. Table 56-2 summarizes the properties of these socket types.

Stream sockets (SOCK_STREAM) provide a reliable, bidirectional, byte-stream communication channel. By the terms in this description, we mean the following:

A stream socket is similar to using a pair of pipes to allow bidirectional communication between two applications, with the difference that (Internet domain) sockets permit communication over a network.

Stream sockets operate in connected pairs. For this reason, stream sockets are described as connection-oriented. The term peer socket refers to the socket at the other end of a connection; peer address denotes the address of that socket; and peer application denotes the application utilizing the peer socket. Sometimes, the term remote (or foreign) is used synonymously with peer. Analogously, sometimes the term local is used to refer to the application, socket, or address for this end of the connection. A stream socket can be connected to only one peer.

Datagram sockets (SOCK_DGRAM) allow data to be exchanged in the form of messages called datagrams. With datagram sockets, message boundaries are preserved, but data transmission is not reliable. Messages may arrive out of order, be duplicated, or not arrive at all.

Datagram sockets are an example of the more generic concept of a connectionless socket. Unlike a stream socket, a datagram socket doesn’t need to be connected to another socket in order to be used. (In Using connect() with Datagram Sockets, we’ll see that datagram sockets may be connected with one another, but this has somewhat different semantics from connected stream sockets.)

In the Internet domain, datagram sockets employ the User Datagram Protocol (UDP), and stream sockets (usually) employ the Transmission Control Protocol (TCP). Instead of using the terms Internet domain datagram socket and Internet domain stream socket, we’ll often just use the terms UDP socket and TCP socket, respectively.

The key socket system calls are the following:

Socket I/O can be performed using the conventional read() and write() system calls, or using a range of socket-specific system calls (e.g., send(), recv(), sendto(), and recvfrom()). By default, these system calls block if the I/O operation can’t be completed immediately. Nonblocking I/O is also possible, by using the fcntl() F_SETFL operation (Open File Status Flags) to enable the O_NONBLOCK open file status flag.

Note

On Linux, we can call ioctl(fd, FIONREAD, &cnt) to obtain the number of unread bytes available on the stream socket referred to by the file descriptor fd. For a datagram socket, this operation returns the number of bytes in the next unread datagram (which may be zero if the next datagram is of zero length), or zero if there are no pending datagrams. This feature is not specified in SUSv3.