MirOS Manual: 20.ipctut(PSD)


          Introductory 4.4BSD IPC                             PSD:20-1

                             An Introductory 4.4BSD
                      Interprocess Communication Tutorial

                                Stuart Sechrest

                        Computer Science Research Group
                           Computer Science Division
           Department of Electrical Engineering and Computer Science
                       University of California, Berkeley

                                    ABSTRACT

                 Berkeley UNIX- 4.4BSD offers several choices for inter-
            process  communication. To aid the programmer in  developing
            programs which are comprised of cooperating  processes,  the
            different choices are discussed and a series of example pro-
            grams 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 docu-
            ment  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  addi-
          tions  and  some  changes to the system 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 com-
          munication 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
          ____________________
             -UNIX is a trademark of AT&T Bell Laboratories.

          PSD:20-2                             Introductory 4.4BSD IPC

          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 mechanism 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  communica-
          tion.

               The identification of IPC with I/O is quite  longstand-
          ing in UNIX and has proved quite successful.  At first, how-
          ever, 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  necessi-
          tated  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 possibilities
          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  wait-
          ing  if  nothing is immediately available.  These new possi-
          bilities 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 processes and interprocess communication. The paper
          reviews the notion of a process and the types of  communica-
          tion that are supported by Berkeley UNIX 4.4BSD. A series of
          examples are presented that create processes  that  communi-
          cate  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 communication 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  program-
          mer  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

          Introductory 4.4BSD IPC                             PSD:20-3

          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
          parent 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 represent
          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 program 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 program, 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

          PSD:20-4                             Introductory 4.4BSD IPC

          #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);
                  }

                  if ((child = fork()) == -1)
                          perror("fork");
                  else if (child) {
                          char buf[1024];

                          /* This is still the parent.  It reads the child's message. */
                          close(sockets[1]);
                          if (read(sockets[0], buf, 1024) < 0)
                                  perror("reading message");
                          printf("-->%s\n", buf);
                          close(sockets[0]);
                  } else {
                          /* This is the child.  It writes a message to its parent. */
                          close(sockets[0]);
                          if (write(sockets[1], DATA, sizeof(DATA)) < 0)
                                  perror("writing message");
                          close(sockets[1]);
                  }
          }
                            Figure 1  Use of a pipe

          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  pro-
          cess that will execute prog2 can substitute the opposite end
          of the pipe for stdin.

          Introductory 4.4BSD IPC                             PSD:20-5

               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  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 pos-
          sible (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 descrip-
          tors be closed, but it is good practice.) A pipe is  also  a
          stream  communication  mechanism; that is, all messages sent
          through the pipe are 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 sockets for one-way
          stream communication.  One may obtain a  pair  of  connected
          sockets for two-way stream communication by calling the rou-
          tine  socketpair().  The   program   in   Figure   3   calls

          PSD:20-6                             Introductory 4.4BSD IPC

                                        arc at 5.407,4.723 from 5.375,4.838 to 5.362,4.612 cw
                                        arc at 5.907,7.973 from 5.875,8.088 to 5.862,7.862 cw
                                        line from 5.963,5.513 to 6.925,5.513
                                        line from 5.963,5.650 to 6.925,5.650
                                        line from 5.963,5.787 to 6.925,5.787
                                        line from 5.963,5.912 to 6.925,5.912
                                        line from 5.963,6.050 to 6.925,6.050
                                        line from 5.963,6.200 to 6.925,6.200 to 6.925,5.375 to 5.963,5.375 to 5.963,6.200
                                        ellipse at 6.388,6.713 wid 0.475 ht 0.475
                                        line from 6.388,6.463 to 6.388,6.200
                                        line from 3.150,6.200 to 4.112,6.200 to 4.112,5.375 to 3.150,5.375 to 3.150,6.200
                                        line from 3.150,6.050 to 4.112,6.050
                                        line from 3.150,5.912 to 4.112,5.912
                                        line from 3.150,5.787 to 4.112,5.787
                                        line from 3.150,5.650 to 4.112,5.650
                                        line from 3.150,5.513 to 4.112,5.513
                                        ellipse at 3.575,6.713 wid 0.475 ht 0.475
                                        line from 3.575,6.463 to 3.575,6.200
                                        line from 3.650,8.762 to 4.612,8.762
                                        line from 3.650,8.900 to 4.612,8.900
                                        line from 3.650,9.037 to 4.612,9.037
                                        line from 3.650,9.162 to 4.612,9.162
                                        line from 3.650,9.300 to 4.612,9.300
                                        line from 3.650,9.450 to 4.612,9.450 to 4.612,8.625 to 3.650,8.625 to 3.650,9.450
                                        ellipse at 4.075,9.963 wid 0.475 ht 0.475
                                        ellipse at 3.950,4.725 wid 0.225 ht 0.225
                                        ellipse at 4.450,7.975 wid 0.225 ht 0.225
                                        dashwid = 0.037i
                                        line dotted from 1.925,7.513 to 8.238,7.513
                                        line from 6.050,6.138 to 5.737,6.138 to 5.737,4.700 to 5.550,4.700
                                        line from 5.650,4.725 to 5.550,4.700 to 5.650,4.675
                                        line from 6.050,6.013 to 4.050,4.888
                                        line from 4.125,4.958 to 4.050,4.888 to 4.149,4.915
                                        line from 3.975,6.000 to 4.525,5.987 to 3.925,4.875
                                        line from 3.950,4.975 to 3.925,4.875 to 3.994,4.951
                                        line from 3.975,6.112 to 5.650,6.112 to 5.650,4.750 to 5.550,4.763
                                        line from 5.652,4.775 to 5.550,4.763 to 5.646,4.725
                                        line from 4.075,9.713 to 4.075,9.450
                                        line from 4.475,9.363 to 6.150,9.363 to 6.150,8.000 to 6.050,8.012
                                        line from 6.152,8.025 to 6.050,8.012 to 6.146,7.975
                                        line from 4.475,9.250 to 5.025,9.238 to 4.425,8.125
                                        line from 4.450,8.225 to 4.425,8.125 to 4.494,8.201
                                        line from 4.362,4.775 to 4.162,4.725 to 4.362,4.675
                                        line from 4.162,4.725 to 4.838,4.725
                                        line from 3.962,4.600 to 5.375,4.600
                                        line from 3.950,4.838 to 5.375,4.838
                                        line from 4.450,8.088 to 5.875,8.088
                                        line from 4.463,7.850 to 5.875,7.850
                                        line from 4.862,8.025 to 4.662,7.975 to 4.862,7.925
                                        line from 4.662,7.975 to 5.338,7.975
                                        "Child" at 6.362,7.106
                                        "Parent" at 3.362,7.096 ljust

          Introductory 4.4BSD IPC                             PSD:20-7

                                        "Parent" at 3.862,10.346 ljust
                                        "PIPE" at 4.987,4.671 ljust
                                        "PIPE" at 5.425,7.921 ljust
               Figure 2  Sharing a pipe between parent and child

          socketpair() to create such a connection.  The program  uses
          the  link for communication in both directions.  Since sock-
          etpairs are an extension of pipes, their use resembles  that
          of  pipes. Figure 4 illustrates the result of a fork follow-
          ing a call to socketpair().

               Socketpair() takes as arguments a  specification  of  a
          domain,  a style of communication, and a protocol. 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 conventions. 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 constants
          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.

          5. Domains and Protocols

               Pipes and socketpairs are a simple solution for commun-
          icating   between  a  parent  and  child  or  between  child
          processes. What if we wanted to have processes that have  no
          common  ancestor  with whom to set up communication? Neither
          standard UNIX pipes nor socketpairs  are  the  answer  here,
          since  both  mechanisms  require a common ancestor to set up
          the communication. We  would  like  to  have  two  processes
          separately  create  sockets  and  then  have  messages  sent
          between them.  This is often  the  case  when  providing  or
          using  a  service in the system.  This is also the case when
          the communicating processes are  on  separate  machines.  In
          Berkeley UNIX 4.4BSD one can create individual sockets, give
          them names and send messages between them.

               Sockets created by  different  programs  use  names  to
          refer  to  one  another;  names generally must be translated
          into addresses for use. The space from which an  address  is
          drawn  is referred to as a domain. There are several domains
          for sockets. Two that will be used in the examples here  are
          the  UNIX  domain  (or AF_UNIX, for Address Format UNIX) and
          the Internet domain (or AF_INET).  UNIX  domain  IPC  is  an
          experimental  facility  in  4.2BSD  and  4.3BSD. In the UNIX
          domain, a socket is given a path name within the file system
          name space. A file system node is created for the socket and

          PSD:20-8                             Introductory 4.4BSD IPC

          #include <sys/types.h>
          #include <sys/socket.h>
          #include <stdio.h>

          #define DATA1 "In Xanadu, did Kublai Khan . . ."
          #define DATA2 "A stately pleasure dome decree . . ."

          /*
           * 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];

                  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
                          perror("opening stream socket pair");
                          exit(1);
                  }

                  if ((child = fork()) == -1)
                          perror("fork");
                  else if (child) {       /* This is the parent. */
                          close(sockets[0]);
                          if (read(sockets[1], buf, 1024, 0) < 0)
                                  perror("reading stream message");
                          printf("-->%s\n", buf);
                          if (write(sockets[1], DATA2, sizeof(DATA2)) < 0)
                                  perror("writing stream message");
                          close(sockets[1]);
                  } else {                /* This is the child. */
                          close(sockets[1]);
                          if (write(sockets[0], DATA1, sizeof(DATA1)) < 0)
                                  perror("writing stream message");
                          if (read(sockets[0], buf, 1024, 0) < 0)
                                  perror("reading stream message");
                          printf("-->%s\n", buf);
                          close(sockets[0]);
                  }
          }
                         Figure 3  Use of a socketpair

          Introductory 4.4BSD IPC                             PSD:20-9

                                        ellipse at 5.787,8.012 wid 0.275 ht 0.275
                                        ellipse at 4.175,8.012 wid 0.275 ht 0.275
                                        dashwid = 0.037i
                                        line dotted from 5.550,8.012 to 4.362,8.012
                                        line from 4.462,8.037 to 4.362,8.012 to 4.462,7.987
                                        line dotted from 4.362,7.950 to 5.550,7.950
                                        line from 5.450,7.925 to 5.550,7.950 to 5.450,7.975
                                        ellipse at 3.737,4.763 wid 0.275 ht 0.275
                                        ellipse at 5.350,4.763 wid 0.275 ht 0.275
                                        line dotted from 3.925,4.700 to 5.112,4.700
                                        line from 5.013,4.675 to 5.112,4.700 to 5.013,4.725
                                        line dotted from 5.112,4.763 to 3.925,4.763
                                        line from 4.025,4.788 to 3.925,4.763 to 4.025,4.737
                                        line from 5.963,5.513 to 6.925,5.513
                                        line from 5.963,5.650 to 6.925,5.650
                                        line from 5.963,5.787 to 6.925,5.787
                                        line from 5.963,5.912 to 6.925,5.912
                                        line from 5.963,6.050 to 6.925,6.050
                                        line from 5.963,6.200 to 6.925,6.200 to 6.925,5.375 to 5.963,5.375 to 5.963,6.200
                                        ellipse at 6.388,6.713 wid 0.475 ht 0.475
                                        line from 6.388,6.463 to 6.388,6.200
                                        line from 3.150,6.200 to 4.112,6.200 to 4.112,5.375 to 3.150,5.375 to 3.150,6.200
                                        line from 3.150,6.050 to 4.112,6.050
                                        line from 3.150,5.912 to 4.112,5.912
                                        line from 3.150,5.787 to 4.112,5.787
                                        line from 3.150,5.650 to 4.112,5.650
                                        line from 3.150,5.513 to 4.112,5.513
                                        ellipse at 3.575,6.713 wid 0.475 ht 0.475
                                        line from 3.575,6.463 to 3.575,6.200
                                        line from 3.650,8.762 to 4.612,8.762
                                        line from 3.650,8.900 to 4.612,8.900
                                        line from 3.650,9.037 to 4.612,9.037
                                        line from 3.650,9.162 to 4.612,9.162
                                        line from 3.650,9.300 to 4.612,9.300
                                        line from 3.650,9.450 to 4.612,9.450 to 4.612,8.625 to 3.650,8.625 to 3.650,9.450
                                        ellipse at 4.075,9.963 wid 0.475 ht 0.475
                                        line from 3.975,6.112 to 5.650,6.112 to 5.650,4.750 to 5.550,4.763
                                        line from 5.652,4.775 to 5.550,4.763 to 5.646,4.725
                                        line from 6.050,6.138 to 5.737,6.138 to 5.737,4.700 to 5.550,4.700
                                        line from 5.650,4.725 to 5.550,4.700 to 5.650,4.675
                                        line dotted from 1.925,7.513 to 8.238,7.513
                                        line from 6.050,6.013 to 4.050,4.888
                                        line from 4.125,4.958 to 4.050,4.888 to 4.149,4.915
                                        line from 3.975,6.000 to 4.525,5.987 to 3.925,4.875
                                        line from 3.950,4.975 to 3.925,4.875 to 3.994,4.951
                                        line from 4.075,9.713 to 4.075,9.450
                                        line from 4.475,9.363 to 6.150,9.363 to 6.150,8.000 to 6.050,8.012
                                        line from 6.152,8.025 to 6.050,8.012 to 6.146,7.975
                                        line from 4.475,9.250 to 5.025,9.238 to 4.425,8.125
                                        line from 4.450,8.225 to 4.425,8.125 to 4.494,8.201
                                        "Child" at 6.362,7.106
                                        "Parent" at 3.362,7.096 ljust
                                        "Parent" at 3.862,10.346 ljust

          PSD:20-10                            Introductory 4.4BSD IPC

            Figure 4  Sharing a socketpair between parent and child

          other processes may then refer to the socket by  giving  the
          proper pathname. UNIX domain names, therefore, allow commun-
          ication between any two processes that work in the same file
          system.  The  Internet  domain is the UNIX implementation of
          the DARPA Internet standard protocols IP/TCP/UDP.  Addresses
          in  the Internet domain consist of a machine network address
          and an identifying number, called a  port.  Internet  domain
          names allow communication between machines.

               Communication  follows   some   particular   ``style.''
          Currently,  communication  is  either through a stream or by
          datagram. Stream communication implies several things.  Com-
          munication takes place across a connection between two sock-
          ets.  The communication is reliable, error-free, and, as  in
          pipes, no message boundaries are kept. Reading from a stream
          may result in reading the data  sent  from  one  or  several
          calls  to  write()  or  only  part of the data from a single
          call, if there is not enough room for the entire message, or
          if   not  all  the  data  from  a  large  message  has  been
          transferred. The protocol implementing  such  a  style  will
          retransmit  messages  received  with  errors.  It  will also
          return error messages if one tries to send a  message  after
          the  connection has been broken. Datagram communication does
          not use connections.  Each message  is  addressed  individu-
          ally.   If  the  address  is  correct,  it will generally be
          received, although this is not guaranteed.  Often  datagrams
          are used for requests that require a response from the reci-
          pient.  If no response arrives in  a  reasonable  amount  of
          time, the request is repeated. The individual datagrams will
          be kept separate when they are read, that is, message  boun-
          daries are preserved.

               The difference in performance between the two styles of
          communication  is  generally less important than the differ-
          ence 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  con-
          sideration.  The  expense of setting up a connection is best
          justified by frequent use of the connection. Since the  per-
          formance  of a protocol changes as it is tuned for different
          situations, it is best to seek the most up-to-date  informa-
          tion  when making choices for a program in which performance
          is crucial.

               A protocol is a set of rules, data formats and  conven-
          tions  that  regulate  the transfer of data between partici-
          pants in the communication. In general, there is one  proto-
          col  for  each  socket  type (stream, datagram, etc.) within
          each domain. The code that implements a protocol keeps track

          Introductory 4.4BSD IPC                            PSD:20-11

          of  the names that are bound to sockets, sets up connections
          and transfers data between sockets, perhaps sending the data
          across  a  network.  This code also keeps track of the names
          that are bound to sockets. It is possible for several proto-
          cols,  differing only in low level details, to implement the
          same style of  communication  within  a  particular  domain.
          Although  it  is possible to select which protocol should be
          used, for nearly all uses it is sufficient  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.

          6. Datagrams in the UNIX Domain

               Let us now look at two  programs  that  create  sockets
          separately.  The  programs in Figures 5a and 5b use datagram
          communication rather than a stream. The  structure  used  to
          name  UNIX domain sockets is defined in the file <sys/un.h>.
          The definition has also been included  in  the  example  for
          clarity.

               Each program creates a socket with a call to  socket().
          These  sockets  are in the UNIX domain. Once a name has been
          decided upon it is attached to a socket by the  system  call
          bind().  The  program in Figure 5a uses the name ``socket'',
          which it binds to its socket. This name will appear  in  the
          working  directory of the program. The routines in Figure 5b
          use its socket only  for  sending  messages.   It  does  not
          create a name for the socket because no other process has to
          refer to it.

               Names in the UNIX domain are  path  names.   Like  file
          path    names    they   may   be   either   absolute   (e.g.
          ``/dev/imaginary'') or relative (e.g.  ``socket'').  Because
          these names are used to allow processes to rendezvous, rela-
          tive path names can pose difficulties  and  should  be  used
          with  care. When a name is bound into the name space, a file
          (inode) is allocated in the file system.  If  the  inode  is
          not  deallocated, the name will continue to exist even after
          the bound socket is closed.  This can cause subsequent  runs
          of  a  program  to  find that a name is unavailable, and can
          cause directories to fill up with these objects.  The  names
          are  removed by calling unlink() or using the rm(1) command.
          Names in the UNIX domain are only used for rendezvous.  They
          are not used for message delivery once a connection is esta-
          blished.  Therefore, in contrast with the  Internet  domain,
          unbound  sockets  need  not  be  (and are not) automatically
          given addresses when they are connected.

          PSD:20-12                            Introductory 4.4BSD IPC

          #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>

          #define NAME "socket"

          /*
           * 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];

                  /* Create socket from which to read. */
                  sock = socket(AF_UNIX, SOCK_DGRAM, 0);
                  if (sock < 0) {
                          perror("opening datagram socket");
                          exit(1);
                  }
                  /* Create name. */
                  name.sun_family = AF_UNIX;
                  strcpy(name.sun_path, NAME);
                  if (bind(sock, &name, sizeof(struct sockaddr_un))) {
                          perror("binding name to datagram socket");
                          exit(1);
                  }
                  printf("socket -->%s\n", NAME);
                  /* Read from the socket */
                  if (read(sock, buf, 1024) < 0)
                          perror("receiving datagram packet");
                  printf("-->%s\n", buf);
                  close(sock);
                  unlink(NAME);
          }
                    Figure 5a  Reading UNIX domain datagrams

          Introductory 4.4BSD IPC                            PSD:20-13

          #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;

                  /* Create socket on which to send. */
                  sock = socket(AF_UNIX, SOCK_DGRAM, 0);
                  if (sock < 0) {
                          perror("opening datagram socket");
                          exit(1);
                  }
                  /* Construct name of socket to send to. */
                  name.sun_family = AF_UNIX;
                  strcpy(name.sun_path, argv[1]);
                  /* Send message. */
                  if (sendto(sock, DATA, sizeof(DATA), 0,
                      &name, sizeof(struct sockaddr_un)) < 0) {
                          perror("sending datagram message");
                  }
                  close(sock);
          }
                   Figure 5b  Sending a UNIX domain datagrams

               There is no established means of communicating names to
          interested  parties.   In the example, the program in Figure
          5b gets the name of the socket to which  it  will  send  its
          message  through its command line arguments.  Once a line of
          communication has been created, one can send  the  names  of
          additional,  perhaps  new, sockets over the link. Facilities
          will have to be built that will  make  the  distribution  of
          names less of a problem than it now is.

          7. Datagrams in the Internet Domain

               The examples in Figure 6a and 6b are very close to  the
          previous  example  except that the socket is in the Internet
          domain.  The  structure  of  Internet  domain  addresses  is
          defined  in  the  file  <netinet/in.h>.  Internet  addresses
          specify a host address (a  32-bit  number)  and  a  delivery

          PSD:20-14                            Introductory 4.4BSD IPC

          #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];

                  /* Create socket from which to read. */
                  sock = socket(AF_INET, SOCK_DGRAM, 0);
                  if (sock < 0) {
                          perror("opening datagram socket");
                          exit(1);
                  }
                  /* Create name with wildcards. */
                  name.sin_family = AF_INET;
                  name.sin_addr.s_addr = INADDR_ANY;
                  name.sin_port = 0;
                  if (bind(sock, &name, sizeof(name))) {
                          perror("binding datagram socket");
                          exit(1);
                  }
                  /* Find assigned port value and print it out. */
                  length = sizeof(name);
                  if (getsockname(sock, &name, &length)) {
                          perror("getting socket name");
                          exit(1);
                  }
                  printf("Socket has port #%d\n", ntohs(name.sin_port));
                  /* Read from the socket */
                  if (read(sock, buf, 1024) < 0)
                          perror("receiving datagram packet");
                  printf("-->%s\n", buf);
                  close(sock);
          }
                  Figure 6a  Reading Internet domain datagrams

          Introductory 4.4BSD IPC                            PSD:20-15

          slot, or port, on that machine.  These ports are managed  by
          the  system  routines  that implement a particular protocol.
          Unlike UNIX domain names,  Internet  socket  names  are  not
          entered  into  the  file  system and, therefore, they do not
          have to be unlinked after the socket has been closed. When a
          message must be sent between machines it is sent to the pro-
          tocol routine on the destination machine,  which  interprets
          the  address to determine to which socket the message should
          be delivered. Several different protocols may be  active  on
          the same machine, but, in general, they will not communicate
          with one another.  As  a  result,  different  protocols  are
          allowed  to  use the same port numbers. Thus, implicitly, an
          Internet address is a triple including a protocol as well as
          the  port and machine address. An association is a temporary
          or permanent specification of a pair of communicating  sock-
          ets.  An association is thus identified by the tuple <proto-
          col, local  machine  address,  local  port,  remote  machine
          address,  remote port>. An association may be transient when
          using datagram sockets; the association actually exists dur-
          ing a send operation.

               The protocol for a socket is chosen when the socket  is
          created.   The local machine address for a socket can be any
          valid network address of the machine, if it  has  more  than
          one,  or  it can be the wildcard value INADDR_ANY. The wild-
          card value is used in the program in Figure 6a. If a machine
          has  several  network  addresses, it is likely that messages
          sent to any of the addresses  should  be  deliverable  to  a
          socket.   This  will  be  the case if the wildcard value has
          been chosen. Note that even if the wildcard value is chosen,
          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 struc-
          ture includes the host's network address,  which  is  copied
          into  the  structure  specifying the destination of the mes-
          sage.

               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  gen-
          eral  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 expli-
          cit 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

          PSD:20-16                            Introductory 4.4BSD IPC

          #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();

                  /* Create socket on which to send. */
                  sock = socket(AF_INET, SOCK_DGRAM, 0);
                  if (sock < 0) {
                          perror("opening datagram socket");
                          exit(1);
                  }
                  /*
                   * Construct name, with no wildcards, of the socket to send to.
                   * Getnostbyname() returns a structure including the network address
                   * of the specified host.  The port number is taken from the command
                   * line.
                   */
                  hp = gethostbyname(argv[1]);
                  if (hp == 0) {
                          fprintf(stderr, "%s: unknown host0, argv[1]);
                          exit(2);
                  }
                  memmove(&name.sin_addr, hp->h_addr, hp->h_length);
                  name.sin_family = AF_INET;
                  name.sin_port = htons(atoi(argv[2]));
                  /* Send message. */
                  if (sendto(sock, DATA, sizeof(DATA), 0, &name, sizeof(name)) < 0)
                          perror("sending datagram message");
                  close(sock);
          }
                 Figure 6b  Sending an Internet domain datagram

          getsockname() to discover what port was  actually  assigned.
          The  routine  getsockname()  will  not work for names in the
          UNIX domain.

          Introductory 4.4BSD IPC                            PSD:20-17

               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 representation they ordi-
          narily use to represent  integers,  printing  out  the  port
          number  as  returned by getsockname() may result in a misin-
          terpretation.  To print out the number, it is  necessary  to
          use the routine ntohs() (for network to host: short) to con-
          vert the number  from  the  network  representation  to  the
          host's  representation.   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 rou-
          tine exists to convert a short integer from the host  format
          to  the  network  format,  called  htons(); similar routines
          exist for long integers. For further information,  refer  to
          the entry for byteorder in section 3 of the manual.

          8. Connections

               To send data between stream sockets (having  communica-
          tion style SOCK_STREAM), the sockets must be connected. Fig-
          ures 7a and 7b show two programs that create such a  connec-
          tion.  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  des-
          troyed  when  either  socket is closed (or soon thereafter).
          If a process persists in sending messages after the  connec-
          tion  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 connection 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 end-
          point for communication within this process for this connec-
          tion.  A  connection  may  be  destroyed  by   closing   the

          PSD:20-18                            Introductory 4.4BSD IPC

          #include <sys/types.h>
          #include <sys/socket.h>
          #include <netinet/in.h>
          #include <netdb.h>
          #include <stdio.h>

          #define DATA "Half a league, half a league . . ."

          /*
           * 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);
                  }
                  memmove(&server.sin_addr, hp->h_addr, hp->h_length);
                  server.sin_port = htons(atoi(argv[2]));

                  if (connect(sock, &server, sizeof(server)) < 0) {
                          perror("connecting stream socket");
                          exit(1);
                  }
                  if (write(sock, DATA, sizeof(DATA)) < 0)
                          perror("writing on stream socket");
                  close(sock);
          }
           Figure 7a  Initiating an Internet domain stream connection

          Introductory 4.4BSD IPC                            PSD:20-19

          #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));

                  /* Start accepting connections */
                  listen(sock, 5);
                  do {
                          msgsock = accept(sock, 0, 0);
                          if (msgsock == -1)
                                  perror("accept");
                          else do {
                                  bzero(buf, sizeof(buf));

          PSD:20-20                            Introductory 4.4BSD IPC

                                  if ((rval = read(msgsock, buf, 1024)) < 0)
                                          perror("reading stream message");
                                  i = 0;
                                  if (rval == 0)
                                          printf("Ending connection\n");
                                  else
                                          printf("-->%s\n", buf);
                          } while (rval != 0);
                          close(msgsock);
                  } while (TRUE);
                  /*
                   * Since this program has an infinite loop, the socket "sock" is
                   * never explicitly closed.  However, all sockets will be closed
                   * automatically when a process is killed or terminates normally.
                   */
          }
           Figure 7b  Accepting an Internet domain stream connection

          #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-21

                          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));

                  /* Start accepting connections */
                  listen(sock, 5);
                  do {
                          FD_ZERO(&ready);
                          FD_SET(sock, &ready);
                          to.tv_sec = 5;
                          if (select(sock + 1, &ready, 0, 0, &to) < 0) {
                                  perror("select");
                                  continue;
                          }
                          if (FD_ISSET(sock, &ready)) {
                                  msgsock = accept(sock, (struct sockaddr *)0, (int *)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);
                          } else
                                  printf("Do something else\n");
                  } while (TRUE);
          }
           Figure 7c  Using select() to check for pending connections

          PSD:20-22                            Introductory 4.4BSD IPC

                                        "Process 1" at 3.800,7.106 rjust
                                        "Process 2" at 6.612,7.106 rjust
                                        line from 3.150,6.200 to 4.112,6.200 to 4.112,5.375 to 3.150,5.375 to 3.150,6.200
                                        line from 3.150,6.050 to 4.112,6.050
                                        line from 3.150,5.912 to 4.112,5.912
                                        line from 3.150,5.787 to 4.112,5.787
                                        line from 3.150,5.650 to 4.112,5.650
                                        line from 3.150,5.513 to 4.112,5.513
                                        ellipse at 3.575,6.713 wid 0.475 ht 0.475
                                        line from 3.575,6.463 to 3.575,6.200
                                        line from 5.963,5.513 to 6.925,5.513
                                        line from 5.963,5.650 to 6.925,5.650
                                        line from 5.963,5.787 to 6.925,5.787
                                        line from 5.963,5.912 to 6.925,5.912
                                        line from 5.963,6.050 to 6.925,6.050
                                        line from 5.963,6.200 to 6.925,6.200 to 6.925,5.375 to 5.963,5.375 to 5.963,6.200
                                        ellipse at 6.388,6.713 wid 0.475 ht 0.475
                                        line from 6.388,6.463 to 6.388,6.200
                                        line from 3.087,8.637 to 4.050,8.637
                                        line from 3.087,8.775 to 4.050,8.775
                                        line from 3.087,8.912 to 4.050,8.912
                                        line from 3.087,9.037 to 4.050,9.037
                                        line from 3.087,9.175 to 4.050,9.175
                                        line from 3.087,9.325 to 4.050,9.325 to 4.050,8.500 to 3.087,8.500 to 3.087,9.325
                                        ellipse at 3.513,9.838 wid 0.475 ht 0.475
                                        line from 3.513,9.588 to 3.513,9.325
                                        line from 5.900,9.325 to 6.862,9.325 to 6.862,8.500 to 5.900,8.500 to 5.900,9.325
                                        line from 5.900,9.175 to 6.862,9.175
                                        line from 5.900,9.037 to 6.862,9.037
                                        line from 5.900,8.912 to 6.862,8.912
                                        line from 5.900,8.775 to 6.862,8.775
                                        line from 5.900,8.637 to 6.862,8.637
                                        ellipse at 6.325,9.838 wid 0.475 ht 0.475
                                        line from 6.325,9.588 to 6.325,9.325
                                        "Process 2" at 6.550,10.231 rjust
                                        "Process 1" at 3.737,10.231 rjust
                                        ellipse at 6.112,4.888 wid 0.275 ht 0.275
                                        ellipse at 5.350,4.763 wid 0.275 ht 0.275
                                        ellipse at 3.737,4.763 wid 0.275 ht 0.275
                                        ellipse at 4.550,7.950 wid 0.275 ht 0.275
                                        ellipse at 5.487,7.950 wid 0.275 ht 0.275
                                        line from 6.050,6.013 to 5.175,6.013 to 5.987,5.013
                                        line from 5.905,5.074 to 5.987,5.013 to 5.944,5.106
                                        line from 6.050,6.138 to 5.737,6.138 to 5.737,4.700 to 5.550,4.700
                                        line from 5.650,4.725 to 5.550,4.700 to 5.650,4.675
                                        dashwid = 0.037i
                                        line dotted from 1.925,7.513 to 8.238,7.513
                                        line from 3.975,6.000 to 4.525,5.987 to 3.925,4.875
                                        line from 3.950,4.975 to 3.925,4.875 to 3.994,4.951
                                        line dotted from 5.112,4.763 to 3.925,4.763
                                        line from 4.025,4.788 to 3.925,4.763 to 4.025,4.737
                                        line dotted from 3.925,4.700 to 5.112,4.700
                                        line from 5.013,4.675 to 5.112,4.700 to 5.013,4.725

          Introductory 4.4BSD IPC                            PSD:20-23

                                        line from 6.050,9.012 to 5.487,9.012 to 5.487,8.137
                                        line from 5.462,8.237 to 5.487,8.137 to 5.513,8.237
                                        line from 3.737,9.137 to 4.550,9.137 to 4.550,8.137
                                        line from 4.525,8.237 to 4.550,8.137 to 4.575,8.237
                                        "NAME" at 6.737,4.918 rjust
                                        "NAME" at 6.112,8.043 rjust

                   Figure 8  Establishing a stream connection

          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 listen() for this
          socket. Since several clients may attempt to connect more or
          less simultaneously, a queue of pending connections is main-
          tained 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 connection 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 print-
          ing out the 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 connection 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

          PSD:20-24                            Introductory 4.4BSD IPC

          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 scope of this paper.

          9. Reads, Writes, Recvs, etc.

               UNIX 4.4BSD has several system calls  for  reading  and
          writing  information.  The  simplest  calls  are read()  and
          write(). Write() takes as arguments the index of a  descrip-
          tor,  a pointer to a buffer containing the data and the size
          of the data. The descriptor may indicate either a file or  a
          connected  socket. ``Connected'' can mean either a connected
          stream socket (as described in  Section  8)  or  a  datagram
          socket  for  which  a  connect() call has provided a default
          destination (see the connect()  manual  page).  Read()  also
          takes a descriptor that indicates either a file or a socket.
          Write() requires a connected socket since no destination  is
          specified  in  the parameters of the system call. Read() can
          be used for either a connected  or  an  unconnected  socket.
          These  calls  are, therefore, quite flexible and may be used
          to write applications that require no assumptions about  the
          source  of  their  input or the destination of their output.
          There are variations on read()  and write() that  allow  the
          source  and  destination  of  the  input  and  output to use
          several separate buffers, while retaining the flexibility to
          handle  both files and sockets.  These are readv() and  wri-
          tev(), for read and write vector.

               It is sometimes necessary to send  high  priority  data
          over  a connection that may have unread low priority data at
          the other end.  For example, a user interface process may be
          interpreting commands and sending them on to another process
          through a stream connection. The  user  interface  may  have
          filled  the stream with as yet unprocessed requests when the
          user types a command to  cancel  all  outstanding  requests.
          Rather than have the high priority data wait to be processed
          after the low priority data, it is possible to  send  it  as
          out-of-band  (OOB)  data.   The  notification of pending OOB
          data results in the generation of a SIGURG signal,  if  this
          signal  has  been enabled (see the manual page for signal or
          sigvec). See [Leffler 1986] for a more complete  description
          of  the  OOB mechanism. There are a pair of calls similar to
          read and write that allow  options,  including  sending  and
          receiving  OOB  information;  these  are  send() and recv().
          These  calls  are  used  only  with  sockets;  specifying  a
          descriptor  for a file will result in the return of an error
          status.  These calls also allow peeking at data in a stream.
          That  is, they allow a process to read data without removing
          the data from the stream.  One use of this  facility  is  to
          read  ahead  in  a  stream to determine the size of the next
          item to be read. When not using these options,  these  calls
          have the same functions as read() and write().

          Introductory 4.4BSD IPC                            PSD:20-25

          #include <sys/types.h>
          #include <sys/socket.h>
          #include <sys/un.h>
          #include <stdio.h>

          #define DATA "Half a league, half a league . . ."

          /*
           * 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]);

                  if (connect(sock, &server, sizeof(struct sockaddr_un)) < 0) {
                          close(sock);
                          perror("connecting stream socket");
                          exit(1);
                  }
                  if (write(sock, DATA, sizeof(DATA)) < 0)
                          perror("writing on stream socket");
          }
             Figure 9a  Initiating a UNIX domain stream connection

          #include <sys/types.h>
          #include <sys/socket.h>
          #include <sys/un.h>
          #include <stdio.h>

          #define NAME "socket"

          /*
           * 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

          PSD:20-26                            Introductory 4.4BSD IPC

           * connection breaks, or a termination message comes through, the program
           * accepts a new connection.
           */
          main()
          {
                  int sock, msgsock, rval;
                  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);
                  }
                  /* 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

          Introductory 4.4BSD IPC                            PSD:20-27

               To send datagrams, one must be allowed to  specify  the
          destination.  The  call sendto() takes a destination address
          as an argument and is therefore used for sending  datagrams.
          The  call  recvfrom() is often used to read datagrams, since
          this call returns the address of the sender, if it is avail-
          able,  along  with  the  data. If the identity of the sender
          does not matter, one may use read() or recv().

               Finally, there are a pair of calls that allow the send-
          ing  and  receiving  of messages from multiple buffers, when
          the address of the recipient must be specified.   These  are
          sendmsg() and recvmsg(). These calls are actually quite gen-
          eral and have other uses, including, in the UNIX domain, the
          transmission  of  a  file  descriptor  from  one  process to
          another.

               The various options for reading and writing  are  shown
          in  Figure  10, together with their parameters.  The parame-
          ters for each system call reflect the differences  in  func-
          tion  of  the different calls. In the examples given in this
          paper, the calls read() and write() have been used  whenever
          possible.

          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 presenta-
          tion.   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 communi-
          cation.  The major shortcoming of these mechanisms  is  that
          they  require communicating processes to be descendants of a
          common process.  They do not allow  intermachine  communica-
          tion.

               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 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 per-
          formance requirements of the  application.  Streams  can  be
          both  advantageous and disadvantageous.  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

          PSD:20-28                            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;

                  cc = write(descriptor, buf, nbytes)
                  int cc, descriptor; char *buf; int nbytes;

                  cc = writev(descriptor, iovec, ioveclen)
                  int cc, descriptor; struct iovec *iovec; int ioveclen;

                  /*
                   * 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;

                  cc = sendto(sock, msg, len, flags, to, tolen)
                  int cc, sock; char *msg; int len, flags;
                  struct sockaddr *to; int tolen;

                  cc = sendmsg(sock, msg, flags)
                  int cc, sock; struct msghdr msg[]; int flags;

                  cc = recv(sock, buf, len, flags)
                  int cc, sock; char *buf; int len, flags;

                  cc = recvfrom(sock, buf, len, flags, from, fromlen)
                  int cc, sock; char *buf; int len, flags;
                  struct sockaddr *from; int *fromlen;

                  cc = recvmsg(sock, msg, flags)
                  int cc, socket; struct msghdr msg[]; int flags;

                Figure 10  Varieties of read and write commands

          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-29

          11. What to do Next

               Many of the examples presented here can serve as models
          for  multiprocess  programs  and  for  programs  distributed
          across several machines. In developing  a  new  multiprocess
          program,  it  is  often  easiest  to first write the code to
          create the processes and  communication  paths.  After  this
          code  is  debugged, the code specific to the application can
          be added.

               An introduction to  the  UNIX  system  and  programming
          using  UNIX system calls can be found in [Kernighan and Pike
          1984]. Further documentation of the Berkeley UNIX 4.4BSD IPC
          mechanisms  can  be  found  in  [Leffler  et al. 1986]. More
          detailed information about particular calls and protocols is
          provided  in  sections  2,  3 and 4 of the UNIX Programmer's
          Manual [CSRG 1986]. In particular the following manual pages
          are relevant:

              creating and naming sockets   socket(2), bind(2)
              establishing connections      listen(2), accept(2), connect(2)
              transferring data             read(2), write(2), send(2), recv(2)
              addresses                     inet(4F)
              protocols                     tcp(4P), udp(4P).

              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 report.

               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  author  and
          should not be interpreted as representing official poli-
          cies,  either  expressed  or  implied,  of  the  Defense
          Research Projects Agency or of the US Government.

          PSD:20-30                            Introductory 4.4BSD IPC

              References

              B.W. Kernighan & R. Pike, 1984,
              The UNIX Programming Environment.
              Englewood Cliffs, N.J.: Prentice-Hall.

              B.W. Kernighan & D.M. Ritchie, 1978,
              The C Programming Language,
              Englewood Cliffs, N.J.: Prentice-Hall.

              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.

              Computer Systems Research Group, 1986,
              UNIX Programmer's Manual, 4.4 Berkeley Software Distribution.
              Computer Systems Research Group,
              Department of Electrical Engineering and Computer Science,
              University of California, Berkeley.

Generated on 2014-07-04 21:17:45 by $MirOS: src/scripts/roff2htm,v 1.79 2014/02/10 00:36:11 tg Exp $

These manual pages and other documentation are copyrighted by their respective writers; their source is available at our CVSweb, AnonCVS, and other mirrors. The rest is Copyright © 2002‒2014 The MirOS Project, Germany.
This product includes material provided by Thorsten Glaser.

This manual page’s HTML representation is supposed to be valid XHTML/1.1; if not, please send a bug report – diffs preferred.