Progress
External Program
Interfaces


UNIX Named Pipe Examples

The following examples show different uses of named pipes. To provide a simple example of how named pipes operate, the first example shows how to use the shell to create a named pipe, send a message to it, and read the message back. The second example shows how to use named pipes with Progress.

Example 1 — Creating and Using a Named Pipe From the Shell

In this example, the cat command sets up a message handler routine and the echo command acts as the requestor:

e-pipex1
# Named Pipe Example 1.
#
# Create named pipe...  
mknod trypipe p
# Open named pipe and read message...
cat trypipe &
# Write message...
echo "This is a message!" > trypipe
# Delete pipe...
rm trypipe 

To try this example, run the shell script, e-pipex1.

This script performs the following actions:

  1. The mknod command creates a named pipe called trypipe.
  2. The cat command opens trypipe for reading. It blocks because trypipe has not yet been opened for writing. Notice that an ampersand (&) is present at the end of the cat command; this runs the cat command as a background process.
  3. The echo command opens trypipe for writing and writes a message. The cat command, blocked until now, resumes execution, and the message appears on the display.
  4. The rm command deletes trypipe.
Example 2 — Using a Named Pipe With Progress

Before working with the following procedures, create a copy of the demo database with the PRODB utility:

prodb demo demo 

This example shows a simple user program that sends one line requests to a Progress message handler routine running in the background, and displays the results. The example consists of four files:

A display of these files follows:

e-pipex2
# Named Pipe Example 2.
#
# Create named pipes...
mknod inpipe p
mknod outpipe p
# Start Progress background session with e-pipex2.p running...
bpro demo -1 -p e-pipex2.p
# Run executable e-asksql...
e-asksql
# Terminate Progress background session...
echo "outpipe \"quit\"" > inpipe
cat outpipe
# Delete named pipes...
rm inpipe
rm outpipe 

e-pipex2.p
DEF VAR sql-stmt AS CHAR FORMAT "x(220)".  /* Target variable for the request*/
DEF VAR out-pipe AS CHAR FORMAT "x(32)".  /* Holds the output file or FIFO */

REPEAT:                /* Do forever: */
  INPUT FROM inpipe NO-ECHO.  /* Set up to read from in-FIFO
                         named "inpipe". */
   REPEAT:              /* For each request received: */
    IMPORT out-pipe sql-stmt.  /* Get the output name
                         and the request. */
    OUTPUT TO VALUE(out-pipe) APPEND.  /* Set up to write results. */
    RUN e-do-sql.p sql-stmt.  /* Pass SQL request to sub-proc. */
    OUTPUT CLOSE.
  END.                  /* This loop ends when the in-FIFO
                         is empty. Just reopen it and */
END.                    /*  wait for the next request. */ 

e-do-sql.p
/* This program consists of a single line of code. */

{1} 

e-asksql.c
#include <stdio.h>
#include <fcntl.h>

main()

{
#define  LEN     250
        char   result[LEN];
        int     fdi, fdo, nread;
        char   request[LEN+8]; /* 8 for "outpipe " + punctuation */
        char   *ptr;
        int     validq, i;

        fdi = open("inpipe", O_WRONLY);
        if (fdi < 0) 
        { printf("Error on inpipe open\n"); exit(1);}

        strcpy(request, "outpipe \""); /* request starts with ’outpipe "’ */

        while (1)
        {
          printf("\n\nEnter your request (type [RETURN] to exit):\n");
          ptr = request+9;
          nread = read(0, ptr, LEN);
          if (nread < 2)
              exit(0);
          else
          {
            validq = 1;             /* valid query? */
            for (i = 9; i<nread+9; i++)
                if (request[i] == ’\"’)
                { printf("Use only single quotes in queries.\n");
                  validq = 0;
                  break;
                }
            if (! validq) continue;
            ptr += nread-1;
            *ptr++ = ’\"’;
            *ptr++ = ’\n’;
            *ptr++ = ’\0’;
            write(fdi, request, strlen(request)); 
            sleep(1);
            fdo = open("outpipe", O_RDONLY);
            if (fdo < 0) 
            { printf("Error on outpipe open\n"); exit(1);}

            while ((nread = read(fdo, result, LEN)) != 0)
            {
              result[nread] = ’\0’;
              printf("%s", result);
            }
            close(fdo);
          }
        }
} 

To prepare and run the example, follow these steps:

  1. Use cc to compile and link the requestor source e-asksql.c to produce the executable e-asksql, as shown:
  2. cc e-asksql.c -o e-asksql  
    

  3. Execute the e-pipex2 script to run the example:
  4. e-pipex2 
    

The e-pipex2 script performs the following actions:

  1. It uses mknod to create two named pipes: inpipe and outpipe. Named pipe inpipe carries requests from the requestor to the message handler routine. Named pipe outpipe carries results back in the opposite direction, from the message handler to the requestor.
  2. Figure 4–3 illustrates this process.

    Figure 4–3: Named Pipes and Progress

  3. It starts a background Progress session that runs the message handler procedure, e-pipex2.p , with the demo database. The following line in e-pipex2.p opens the named pipe inpipe for input:
  4. INPUT FROM inpipe NO-ECHO. 
    

    Notice that Progress accesses named pipes in exactly the same way as UNIX text files. At this point, e-pipex2.p blocks until a requestor process opens inpipe for output.

  5. After starting the Progress message handler, the script starts the requestor, e-asksql, which opens inpipe for output using the following statements:
  6. int fdi, fdo, nread;
                .
                .
                .
    fdi = open("inpipe", O_WRONLY); 
    

  7. As e-asksql opens inpipe, e-pipex2.p unblocks and blocks again as it attempts to read a message from inpipe. The message handler procedure, e-pipex2.p, expects single-line requests from requestors, and can handle more than one requestor. This is the syntax for message handler requests:
  8. SYNTAX
    output-pipe-name SQL-statement 
    

    Each request contains the name of the named (output-named-pipe) pipe from which the requestor expects to receive results and an SQL statement (SQL-statement) surrounded by double quotes (" "). The message handler procedure reads these messages with the following statement:

    IMPORT out-pipe sql-stmt. 
    

    Each requestor must specify a unique value for output-pipe-name, or results might be intermixed. (Using the requestor’s PID number as part of the name ensures uniqueness. However, for that to work, the requestor probably has to create its own named pipe using the mknod() system call.) Note that for this example, the requestor, e-asksql, uses the existing named pipe outpipe created by the script.

  9. As the message handler waits for input, the requestor displays the following prompt:
  10. Enter your request (type [RETURN] to exit): 
    

    You can enter a one-line SQL query like the following SELECT from the demo database:

    SELECT name FROM customer. 
    

  11. The requestor constructs a message from the name of the output pipe (outpipe, in the example) and the contents of your query, and writes the message to inpipe, as in the following statements from e-asksql.c:
  12. char request[LEN+8]; /* 8 for "outpipe " + punctuation */
                    .
                    .
                    .
    write(fdi, request, strlen(request)); 
    

  13. As the message handler receives (and removes) the message from inpipe, it unblocks and opens the output pipe named in the message with the following statement:
  14. OUTPUT TO VALUE(out-pipe). 
    

  15. The message handler blocks again, waiting for the requestor to open the same pipe for input (to receive the query result), as in the following statements from e-asksql.c:
  16. int fdi, fdo, nread;
                .
                .
                .
    fdo = open("outpipe", O_RDONLY); 
    

  17. The Progress message handler then continues to compile and run the SQL query using the following statement:
  18. RUN e-do-sql.p sql-stmt. 
    

    As the query generates output, Progress writes it one line at a time to the named pipe specified by outpipe. The requestor reads each line as it is written to the output pipe, as in the following statements from e-asksql. In the example, the requestor also writes each line to its standard output:

    NOTE: If there is no output, you might have entered your SQL statement incorrectly. This causes e-pipex2.p to terminate. To trap this type of error, write the SQL statement to a file instead of to a named pipe, then compile the file. If the compilation is successful, run it.

    char result[LEN];
    int fdi, fdo, nread;int fdi, fdo, nread;
                    .
                    .
                    .
    while ((nread = read(fdo, result, LEN)) != 0)
    {
        result[nread] = ’\0’;
        printf("%s", result);
    } 
    

    Note that although the query procedure, e-do-sql.p, contains only the single procedure parameter, {1}, you can extend it with formatting statements to avoid having to include these in each query, as in the following examples:

    {1} WITH NO-LABELS. 
    

    {1} WITH EXPORT. 
    

  19. The example requestor, e-asksql, continues to prompt for queries, repeating Actions 5 through 9, until you press RETURN with no additional input.
  20. After the requestor terminates, the e-pipex2 script terminates the Progress background process with the following commands:
  21. echo "outpipe \"quit\"" > inpipe
    cat outpipe 
    

    The first command sends the Progress QUIT statement to the message handler (instead of an SQL statement). The second command takes the place of Action 8, originally handled by the requestor. The requestor does not send the QUIT to terminate the Progress background process so that multiple copies of the requestor — each with its own output pipe — can run without affecting the message handler. It is necessary because a process blocks until a named pipe it opens for writing is opened for reading (see the "Operational Characteristics Of Named Pipes" section). In this case, the message handler opens named pipe outpipe for writing, and cannot execute QUIT until the cat command opens outpipe for reading.

  22. The, e-pipex2 script uses the rm command to remove the named pipes that it created.

Copyright © 2004 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095