Plug It In
These days, the most common IPC mechanism is the socket. The Socket API comes from BSD UNIX, unlike the other IPC APIs we’ve discussed, which tend to originate with System V.
Sockets, like pipes, are a mechanism for sending a stream of bytes from one place to another. Like pipes, they’re represented by a file descriptor. Unlike pipes, they’re not limited to local IPC; sockets are also used for network connections.
Berkeley sockets are a bit more flexible than pipes. While pipes are always stream-based, sockets can also be message-based. The other main attribute of a socket is whether it’s connection-oriented or connectionless. A connection-oriented socket behaves like a pipe; data put in one end comes out the other. Data put into connectionless sockets must be associated with a destination address, allowing a single socket to send messages to different destinations. Connectionless sockets often support broadcasting or multicasting, depending on the underlying transport.
The transport used for sockets is configurable, but not all transports support all forms of socket. The following table shows some examples.
Type |
Connectionless |
Connection-Oriented |
Message-based |
UDP |
SCTP |
Stream-based |
N/A |
TCP |
For local communication, you can use either a network protocol over the loopback interface (IP address 127.0.0.1), or UNIX domain sockets.
For communicating between related processes, the easiest mechanism is to use the socketpair(2) call. Similar to the pipe(2) call in terms of syntax, it’s passed an array of two integers that it sets to file descriptors for socket endpoints. This is the syntax of the call:
int socketpair(int domain, int type, int protocol, int socket_vector[2]);
The domain should always be set to AF_UNIX (or AF_LOCAL, which is a synonym), since other mechanisms aren’t widely supported. The protocol can usually be set to 0, which selects the default protocol to use for the type selected. All implementations are required to support the following types:
- SOCK_STREAM provides an interface similar to a bidirectional pipe.
- SOCK_DGRAM provides connectionless unreliable message transmission. These are usually used for UDP connections over a network, and are less relevant to local IPC.
- SOCK_SEQPACKET provides reliable connection-oriented message transmission.
Our last example can be modified trivially to use sockets rather than pipes. The first change required is to add the correct header to the top of the file:
#include <sys/socket.h>
The next change is to modify the pipepair() function to return sockets instead of pipes. This is done by replacing the call to pipe(2) with the following:
socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes)
Since both pipes and sockets are represented by file descriptors, the same operations can be used with both. In addition, sockets support the send(2)/recv(2) style of calls, which provide some extra options.
A better way of implementing message-passing using sockets would be to use a SOCK_SEQPACKET connection. Try modifying the message loop and message-sending code to use this kind of socket. The recvmsg(2) and sendmsg(2) man pages will help you.