Cisco OSPF Design Guide
Cisco OSPF Design Guide
Cisco OSPF Design Guide
An Introductory 4.4BSD
Interprocess Communication Tutorial
Stuart Sechrest
ABSTRACT
Berkeley UNIX† 4.4BSD offers several choices for interprocess communication. To aid the pro-
grammer in developing programs which are comprised of cooperating processes, the different choices are
discussed and a series of example programs are presented. These programs demonstrate in a simple way
the use of pipes, socketpairs, sockets and the use of datagram and stream communication. The intent of this
document is to present a few simple example programs, not to describe the networking system in full.
1. Goals
Facilities for interprocess communication (IPC) and networking were a major addition to UNIX in
the Berkeley UNIX 4.2BSD release. These facilities required major additions and some changes to the sys-
tem interface. The basic idea of this interface is to make IPC similar to file I/O. In UNIX a process has a
set of I/O descriptors, from which one reads and to which one writes. Descriptors may refer to normal files,
to devices (including terminals), or to communication channels. The use of a descriptor has three phases:
its creation, its use for reading and writing, and its destruction. By using descriptors to write files, rather
than simply naming the target file in the write call, one gains a surprising amount of flexibility. Often, the
program that creates a descriptor will be different from the program that uses the descriptor. For example
the shell can create a descriptor for the output of the ‘ls’ command that will cause the listing to appear in a
file rather than on a terminal. Pipes are another form of descriptor that have been used in UNIX for some
time. Pipes allow one-way data transmission from one process to another; the two processes and the pipe
must be set up by a common ancestor.
The use of descriptors is not the only communication interface provided by UNIX. The signal mech-
anism sends a tiny amount of information from one process to another. The signaled process receives only
the signal type, not the identity of the sender, and the number of possible signals is small. The signal
semantics limit the flexibility of the signaling mechanism as a means of interprocess communication.
The identification of IPC with I/O is quite longstanding in UNIX and has proved quite successful. At
first, however, IPC was limited to processes communicating within a single machine. With Berkeley UNIX
4.2BSD this expanded to include IPC between machines. This expansion has necessitated some change in
the way that descriptors are created. Additionally, new possibilities for the meaning of read and write have
been admitted. Originally the meanings, or semantics, of these terms were fairly simple. When you wrote
something it was delivered. When you read something, you were blocked until the data arrived. Other pos-
sibilities exist, however. One can write without full assurance of delivery if one can check later to catch
occasional failures. Messages can be kept as discrete units or merged into a stream. One can ask to read,
but insist on not waiting if nothing is immediately available. These new possibilities are allowed in the
Berkeley UNIX IPC interface.
Thus Berkeley UNIX 4.4BSD offers several choices for IPC. This paper presents simple examples
that illustrate some of the choices. The reader is presumed to be familiar with the C programming language
[Kernighan & Ritchie 1978], but not necessarily with the system calls of the UNIX system or with pro-
cesses and interprocess communication. The paper reviews the notion of a process and the types of com-
munication that are supported by Berkeley UNIX 4.4BSD. A series of examples are presented that create
processes that communicate with one another. The programs show different ways of establishing channels
of communication. Finally, the calls that actually transfer data are reviewed. To clearly present how com-
munication can take place, the example programs have been cleared of anything that might be construed as
useful work. They can, therefore, serve as models for the programmer trying to construct programs which
are comprised of cooperating processes.
2. Processes
A program is both a sequence of statements and a rough way of referring to the computation that
occurs when the compiled statements are run. A process can be thought of as a single line of control in a
program. Most programs execute some statements, go through a few loops, branch in various directions
and then end. These are single process programs. Programs can also have a point where control splits into
two independent lines, an action called forking. In UNIX these lines can never join again. A call to the
system routine fork(), causes a process to split in this way. The result of this call is that two independent
processes will be running, executing exactly the same code. Memory values will be the same for all values
set before the fork, but, subsequently, each version will be able to change only the value of its own copy of
each variable. Initially, the only difference between the two will be the value returned by fork(). The par-
ent will receive a process id for the child, the child will receive a zero. Calls to fork(), therefore, typically
precede, or are included in, an if-statement.
A process views the rest of the system through a private table of descriptors. The descriptors can rep-
resent open files or sockets (sockets are communication objects that will be discussed below). Descriptors
are referred to by their index numbers in the table. The first three descriptors are often known by special
names, stdin, stdout and stderr. These are the standard input, output and error. When a process forks, its
descriptor table is copied to the child. Thus, if the parent’s standard input is being taken from a terminal
(devices are also treated as files in UNIX), the child’s input will be taken from the same terminal. Whoever
reads first will get the input. If, before forking, the parent changes its standard input so that it is reading
from a new file, the child will take its input from the new file. It is also possible to take input from a socket,
rather than from a file.
3. Pipes
Most users of UNIX know that they can pipe the output of a program ‘‘prog1’’ to the input of
another, ‘‘prog2,’’ by typing the command ‘‘prog1 | prog2.’’ This is called ‘‘piping’’ the output of one pro-
gram to another because the mechanism used to transfer the output is called a pipe. When the user types a
command, the command is read by the shell, which decides how to execute it. If the command is simple,
for example, ‘‘prog1,’’ the shell forks a process, which executes the program, prog1, and then dies. The
shell waits for this termination and then prompts for the next command. If the command is a compound
command, ‘‘prog1 | prog2,’’ the shell creates two processes connected by a pipe. One process runs the pro-
gram, prog1, the other runs prog2. The pipe is an I/O mechanism with two ends, or sockets. Data that is
written into one socket can be read from the other.
Since a program specifies its input and output only by the descriptor table indices, which appear as
variables or constants, the input source and output destination can be changed without changing the text of
the program. It is in this way that the shell is able to set up pipes. Before executing prog1, the process can
close whatever is at stdout and replace it with one end of a pipe. Similarly, the process that will execute
prog2 can substitute the opposite end of the pipe for stdin.
Introductory 4.4BSD IPC PSD:20-3
#include <stdio.h>
#define DATA "Bright star, would I were steadfast as thou art . . ."
/*
* This program creates a pipe, then forks. The child communicates to the
* parent over the pipe. Notice that a pipe is a one-way communications
* device. I can write to the output socket (sockets[1], the second socket
* of the array returned by pipe()) and read from the input socket
* (sockets[0]), but not vice versa.
*/
main()
{
int sockets[2], child;
/* Create a pipe */
if (pipe(sockets) < 0) {
perror("opening stream socket pair");
exit(10);
}
Let us now examine a program that creates a pipe for communication between its child and itself
(Figure 1). A pipe is created by a parent process, which then forks. When a process forks, the parent’s
descriptor table is copied into the child’s.
In Figure 1, the parent process makes a call to the system routine pipe(). This routine creates a pipe
and places descriptors for the sockets for the two ends of the pipe in the process’s descriptor table. Pipe() is
passed an array into which it places the index numbers of the sockets it created. The two ends are not
equivalent. The socket whose index is returned in the low word of the array is opened for reading only,
while the socket in the high end is opened only for writing. This corresponds to the fact that the standard
input is the first descriptor of a process’s descriptor table and the standard output is the second. After
PSD:20-4 Introductory 4.4BSD IPC
creating the pipe, the parent creates the child with which it will share the pipe by calling fork(). Figure 2
illustrates the effect of a fork. The parent process’s descriptor table points to both ends of the pipe. After
the fork, both parent’s and child’s descriptor tables point to the pipe. The child can then use the pipe to
send a message to the parent.
Just what is a pipe? It is a one-way communication mechanism, with one end opened for reading and
the other end for writing. Therefore, parent and child need to agree on which way to turn the pipe, from
parent to child or the other way around. Using the same pipe for communication both from parent to child
and from child to parent would be possible (since both processes have references to both ends), but very
complicated. If the parent and child are to have a two-way conversation, the parent creates two pipes, one
for use in each direction. (In accordance with their plans, both parent and child in the example above close
the socket that they will not use. It is not required that unused descriptors be closed, but it is good prac-
tice.) A pipe is also a stream communication mechanism; that is, all messages sent through the pipe are
Parent
PIPE
Parent Child
PIPE
Figure 2 Sharing a pipe between parent and child
Introductory 4.4BSD IPC PSD:20-5
placed in order and reliably delivered. When the reader asks for a certain number of bytes from this stream,
he is given as many bytes as are available, up to the amount of the request. Note that these bytes may have
come from the same call to write() or from several calls to write() which were concatenated.
4. Socketpairs
Berkeley UNIX 4.4BSD provides a slight generalization of pipes. A pipe is a pair of connected sock-
ets for one-way stream communication. One may obtain a pair of connected sockets for two-way stream
communication by calling the routine socketpair(). The program in Figure 3 calls socketpair() to create
such a connection. The program uses the link for communication in both directions. Since socketpairs are
an extension of pipes, their use resembles that of pipes. Figure 4 illustrates the result of a fork following a
call to socketpair().
Socketpair() takes as arguments a specification of a domain, a style of communication, and a proto-
col. These are the parameters shown in the example. Domains and protocols will be discussed in the next
section. Briefly, a domain is a space of names that may be bound to sockets and implies certain other con-
ventions. Currently, socketpairs have only been implemented for one domain, called the UNIX domain.
The UNIX domain uses UNIX path names for naming sockets. It only allows communication between
sockets on the same machine.
Note that the header files <sys/socket.h> and <sys/types.h>. are required in this program. The con-
stants AF_UNIX and SOCK_STREAM are defined in <sys/socket.h>, which in turn requires the file
<sys/types.h> for some of its definitions.
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
/*
* This program creates a pair of connected sockets then forks and
* communicates over them. This is very similar to communication with pipes,
* however, socketpairs are two-way communications objects. Therefore I can
* send messages in both directions.
*/
main()
{
int sockets[2], child;
char buf[1024];
Parent
Parent Child
arrives in a reasonable amount of time, the request is repeated. The individual datagrams will be kept sepa-
rate when they are read, that is, message boundaries are preserved.
The difference in performance between the two styles of communication is generally less important
than the difference in semantics. The performance gain that one might find in using datagrams must be
weighed against the increased complexity of the program, which must now concern itself with lost or out of
order messages. If lost messages may simply be ignored, the quantity of traffic may be a consideration.
The expense of setting up a connection is best justified by frequent use of the connection. Since the perfor-
mance of a protocol changes as it is tuned for different situations, it is best to seek the most up-to-date
information when making choices for a program in which performance is crucial.
A protocol is a set of rules, data formats and conventions that regulate the transfer of data between
participants in the communication. In general, there is one protocol for each socket type (stream, datagram,
etc.) within each domain. The code that implements a protocol keeps track of the names that are bound to
sockets, sets up connections and transfers data between sockets, perhaps sending the data across a net-
work. This code also keeps track of the names that are bound to sockets. It is possible for several
PSD:20-8 Introductory 4.4BSD IPC
protocols, differing only in low level details, to implement the same style of communication within a partic-
ular domain. Although it is possible to select which protocol should be used, for nearly all uses it is suffi-
cient to request the default protocol. This has been done in all of the example programs.
One specifies the domain, style and protocol of a socket when it is created. For example, in Figure 5a
the call to socket() causes the creation of a datagram socket with the default protocol in the UNIX domain.
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
/*
* In the included file <sys/un.h> a sockaddr_un is defined as follows
* struct sockaddr_un {
* short sun_family;
* char sun_path[108];
* };
*/
#include <stdio.h>
/*
* This program creates a UNIX domain datagram socket, binds a name to it,
* then reads from the socket.
*/
main()
{
int sock, length;
struct sockaddr_un name;
char buf[1024];
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#define DATA "The sea is calm tonight, the tide is full . . ."
/*
* Here I send a datagram to a receiver whose name I get from the command
* line arguments. The form of the command line is udgramsend pathname
*/
main(argc, argv)
int argc;
char *argv[];
{
int sock;
struct sockaddr_un name;
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
/*
* In the included file <netinet/in.h> a sockaddr_in is defined as follows:
* struct sockaddr_in {
* short sin_family;
* u_short sin_port;
* struct in_addr sin_addr;
* char sin_zero[8];
* };
*
* This program creates a datagram socket, binds a name to it, then reads
* from the socket.
*/
main()
{
int sock, length;
struct sockaddr_in name;
char buf[1024];
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#define DATA "The sea is calm tonight, the tide is full . . ."
/*
* Here I send a datagram to a receiver whose name I get from the command
* line arguments. The form of the command line is dgramsend hostname
* portnumber
*/
main(argc, argv)
int argc;
char *argv[];
{
int sock;
struct sockaddr_in name;
struct hostent *hp, *gethostbyname();
a program sending messages to the named socket must specify a valid network address. One can be willing
to receive from ‘‘anywhere,’’ but one cannot send a message ‘‘anywhere.’’ The program in Figure 6b is
given the destination host name as a command line argument. To determine a network address to which it
can send the message, it looks up the host address by the call to gethostbyname(). The returned structure
Introductory 4.4BSD IPC PSD:20-13
includes the host’s network address, which is copied into the structure specifying the destination of the
message.
The port number can be thought of as the number of a mailbox, into which the protocol places one’s
messages. Certain daemons, offering certain advertised services, have reserved or ‘‘well-known’’ port
numbers. These fall in the range from 1 to 1023. Higher numbers are available to general users. Only
servers need to ask for a particular number. The system will assign an unused port number when an address
is bound to a socket. This may happen when an explicit bind call is made with a port number of 0, or when
a connect or send is performed on an unbound socket. Note that port numbers are not automatically
reported back to the user. After calling bind(), asking for port 0, one may call getsockname() to discover
what port was actually assigned. The routine getsockname() will not work for names in the UNIX domain.
The format of the socket address is specified in part by standards within the Internet domain. The
specification includes the order of the bytes in the address. Because machines differ in the internal repre-
sentation they ordinarily use to represent integers, printing out the port number as returned by getsock-
name() may result in a misinterpretation. To print out the number, it is necessary to use the routine ntohs()
(for network to host: short) to convert the number from the network representation to the host’s representa-
tion. On some machines, such as 68000-based machines, this is a null operation. On others, such as
VAXes, this results in a swapping of bytes. Another routine exists to convert a short integer from the host
format to the network format, called htons(); similar routines exist for long integers. For further informa-
tion, refer to the entry for byteorder in section 3 of the manual.
8. Connections
To send data between stream sockets (having communication style SOCK_STREAM), the sockets
must be connected. Figures 7a and 7b show two programs that create such a connection. The program in
7a is relatively simple. To initiate a connection, this program simply creates a stream socket, then calls
connect(), specifying the address of the socket to which it wishes its socket connected. Provided that the
target socket exists and is prepared to handle a connection, connection will be complete, and the program
can begin to send messages. Messages will be delivered in order without message boundaries, as with
pipes. The connection is destroyed when either socket is closed (or soon thereafter). If a process persists in
sending messages after the connection is closed, a SIGPIPE signal is sent to the process by the operating
system. Unless explicit action is taken to handle the signal (see the manual page for signal or sigvec), the
process will terminate and the shell will print the message ‘‘broken pipe.’’
Forming a connection is asymmetrical; one process, such as the program in Figure 7a, requests a con-
nection with a particular socket, the other process accepts connection requests. Before a connection can be
accepted a socket must be created and an address bound to it. This situation is illustrated in the top half of
Figure 8. Process 2 has created a socket and bound a port number to it. Process 1 has created an unnamed
socket. The address bound to process 2’s socket is then made known to process 1 and, perhaps to several
other potential communicants as well. If there are several possible communicants, this one socket might
receive several requests for connections. As a result, a new socket is created for each connection. This new
socket is the endpoint for communication within this process for this connection. A connection may be
destroyed by closing the corresponding socket.
The program in Figure 7b is a rather trivial example of a server. It creates a socket to which it binds a
name, which it then advertises. (In this case it prints out the socket number.) The program then calls lis-
ten() for this socket. Since several clients may attempt to connect more or less simultaneously, a queue of
pending connections is maintained in the system address space. Listen() marks the socket as willing to
accept connections and initializes the queue. When a connection is requested, it is listed in the queue. If
the queue is full, an error status may be returned to the requester. The maximum length of this queue is
specified by the second argument of listen(); the maximum length is limited by the system. Once the listen
call has been completed, the program enters an infinite loop. On each pass through the loop, a new connec-
tion is accepted and removed from the queue, and, hence, a new socket for the connection is created. The
bottom half of Figure 8 shows the result of Process 1 connecting with the named socket of Process 2, and
Process 2 accepting the connection. After the connection is created, the service, in this case printing out the
PSD:20-14 Introductory 4.4BSD IPC
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
/*
* This program creates a socket and initiates a connection with the socket
* given in the command line. One message is sent over the connection and
* then the socket is closed, ending the connection. The form of the command
* line is streamwrite hostname portnumber
*/
main(argc, argv)
int argc;
char *argv[];
{
int sock;
struct sockaddr_in server;
struct hostent *hp, *gethostbyname();
char buf[1024];
/* Create socket */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/* Connect socket using name specified by command line. */
server.sin_family = AF_INET;
hp = gethostbyname(argv[1]);
if (hp == 0) {
fprintf(stderr, "%s: unknown host0, argv[1]);
exit(2);
}
bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
server.sin_port = htons(atoi(argv[2]));
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#define TRUE 1
/*
* This program creates a socket and then begins an infinite loop. Each time
* through the loop it accepts a connection and prints out messages from it.
* When the connection breaks, or a termination message comes through, the
* program accepts a new connection.
*/
main()
{
int sock, length;
struct sockaddr_in server;
int msgsock;
char buf[1024];
int rval;
int i;
/* Create socket */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/* Name socket using wildcards */
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = 0;
if (bind(sock, &server, sizeof(server))) {
perror("binding stream socket");
exit(1);
}
/* Find out assigned port number and print it out */
length = sizeof(server);
if (getsockname(sock, &server, &length)) {
perror("getting socket name");
exit(1);
}
printf("Socket has port #%d\n", ntohs(server.sin_port));
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#define TRUE 1
/*
* This program uses select() to check that someone is trying to connect
* before calling accept().
*/
main()
{
int sock, length;
struct sockaddr_in server;
int msgsock;
char buf[1024];
int rval;
fd_set ready;
struct timeval to;
/* Create socket */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/* Name socket using wildcards */
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = 0;
if (bind(sock, &server, sizeof(server))) {
Introductory 4.4BSD IPC PSD:20-17
Process 1 Process 2
NAME
Process 1 Process 2
NAME
messages, is performed and the connection socket closed. The accept() call will take a pending connection
request from the queue if one is available, or block waiting for a request. Messages are read from the con-
nection socket. Reads from an active connection will normally block until data is available. The number of
bytes read is returned. When a connection is destroyed, the read call returns immediately. The number of
bytes returned will be zero.
The program in Figure 7c is a slight variation on the server in Figure 7b. It avoids blocking when
there are no pending connection requests by calling select() to check for pending requests before calling
accept(). This strategy is useful when connections may be received on more than one socket, or when data
may arrive on other connected sockets before another connection request.
The programs in Figures 9a and 9b show a program using stream communication in the UNIX
domain. Streams in the UNIX domain can be used for this sort of program in exactly the same way as
Internet domain streams, except for the form of the names and the restriction of the connections to a single
file system. There are some differences, however, in the functionality of streams in the two domains,
notably in the handling of out-of-band data (discussed briefly below). These differences are beyond the
Introductory 4.4BSD IPC PSD:20-19
10. Choices
This paper has presented examples of some of the forms of communication supported by Berkeley
UNIX 4.4BSD. These have been presented in an order chosen for ease of presentation. It is useful to
review these options emphasizing the factors that make each attractive.
Pipes have the advantage of portability, in that they are supported in all UNIX systems. They also are
relatively simple to use. Socketpairs share this simplicity and have the additional advantage of allowing
bidirectional communication. The major shortcoming of these mechanisms is that they require communi-
cating processes to be descendants of a common process. They do not allow intermachine communication.
The two communication domains, UNIX and Internet, allow processes with no common ancestor to
communicate. Of the two, only the Internet domain allows communication between machines. This makes
PSD:20-20 Introductory 4.4BSD IPC
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
/*
* This program connects to the socket named in the command line and sends a
* one line message to that socket. The form of the command line is
* ustreamwrite pathname
*/
main(argc, argv)
int argc;
char *argv[];
{
int sock;
struct sockaddr_un server;
char buf[1024];
/* Create socket */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/* Connect socket using name specified by command line. */
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[1]);
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
/*
* This program creates a socket in the UNIX domain and binds a name to it.
* After printing the socket’s name it begins a loop. Each time through the
* loop it accepts a connection and prints out messages from it. When the
Introductory 4.4BSD IPC PSD:20-21
/* Create socket */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/* Name socket using file system name */
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
/* Start accepting connections */
listen(sock, 5);
for (;;) {
msgsock = accept(sock, 0, 0);
if (msgsock == -1)
perror("accept");
else do {
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
/*
* The following statements are not executed, because they follow an
* infinite loop. However, most ordinary programs will not run
* forever. In the UNIX domain it is necessary to tell the file
* system that one is through using NAME. In most programs one uses
* the call unlink() as below. Since the user will have to kill this
* program, it will be necessary to remove the name by a command from
* the shell.
*/
close(sock);
unlink(NAME);
}
Figure 9b Accepting a UNIX domain stream connection
PSD:20-22 Introductory 4.4BSD IPC
/*
* The variable descriptor may be the descriptor of either a file
* or of a socket.
*/
cc = read(descriptor, buf, nbytes)
int cc, descriptor; char *buf; int nbytes;
/*
* An iovec can include several source buffers.
*/
cc = readv(descriptor, iov, iovcnt)
int cc, descriptor; struct iovec *iov; int iovcnt;
/*
* The variable ‘‘sock’’ must be the descriptor of a socket.
* Flags may include MSG_OOB and MSG_PEEK.
*/
cc = send(sock, msg, len, flags)
int cc, sock; char *msg; int len, flags;
the Internet domain a necessary choice for processes running on separate machines.
The choice between datagrams and stream communication is best made by carefully considering the
semantic and performance requirements of the application. Streams can be both advantageous and disad-
vantageous. One disadvantage is that a process is only allowed a limited number of open streams, as there
are usually only 64 entries available in the open descriptor table. This can cause problems if a single server
must talk with a large number of clients. Another is that for delivering a short message the stream setup
and teardown time can be unnecessarily long. Weighed against this are the reliability built into the streams.
This will often be the deciding factor in favor of streams.
Introductory 4.4BSD IPC PSD:20-23
Acknowledgements
I would like to thank Sam Leffler and Mike Karels for their help in understanding the IPC
mechanisms and all the people whose comments have helped in writing and improving this re-
port.
This work was sponsored by the Defense Advanced Research Projects Agency (DoD),
ARPA Order No. 4031, monitored by the Naval Electronics Systems Command under contract
No. N00039-C-0235. The views and conclusions contained in this document are those of the au-
thor and should not be interpreted as representing official policies, either expressed or implied, of
the Defense Research Projects Agency or of the US Government.
References
S.J. Leffler, R.S. Fabry, W.N. Joy, P. Lapsley, S. Miller & C. Torek, 1986,
An Advanced 4.4BSD Interprocess Communication Tutorial.
Computer Systems Research Group,
Department of Electrical Engineering and Computer Science,
University of California, Berkeley.