0% found this document useful (0 votes)
49 views13 pages

02 CPipeShell

This document discusses pipes and FIFOs in UNIX systems. It defines a pipe as a one-way communication channel that can be used to link processes. Pipes allow standard output of one process to be fed as standard input to another process concurrently. An example is provided of using the shell pipe operator "|" to couple the output of a "who" command to the input of a "wc -l" command to count the number of logged in users. Programming with pipes using the pipe() system call is also outlined.

Uploaded by

John Smith
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views13 pages

02 CPipeShell

This document discusses pipes and FIFOs in UNIX systems. It defines a pipe as a one-way communication channel that can be used to link processes. Pipes allow standard output of one process to be fed as standard input to another process concurrently. An example is provided of using the shell pipe operator "|" to couple the output of a "who" command to the input of a "wc -l" command to count the number of logged in users. Programming with pipes using the pipe() system call is also outlined.

Uploaded by

John Smith
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Outline

●  What is a pipe?
CSCI 4730/6730 ●  UNIX System review
Systems Programming Refresher ●  Processes (review)
●  Pipes
●  FIFOs
Pipes & FIFOs

Maria Hybinette, UGA 1 Maria Hybinette, UGA 2

What is a Pipe? Example: Shell Pipes


●  Example:
●  A pipe is a one-way (half-duplex) »  who
communication channel which can be used –  outputs who is logged onto the system (e.g. on atlas)
to link processes. »  wc -l hello.txt
–  outputs counts the number of lines in the file hello.txt
●  Can only be used between processes that ●  You have seen pipes at the UNIX shell level already:
have a common ancestor »  who | wc -l

●  A pipe is a generalization of the file concept ●  Shell starts the commands who and wc -l to run
concurrently.
»  can use I/O functions like read()and write()to ●  | tells the shell to create a pipe to couple standard
receive and send data output of who to the standard input of wc -l , Recall < and >
logically: redirects
»  {atlas:maria:195} who > tmpfile standard input
and output to a
»  {atlas:maria:196} wc -l < tmpfile file (i.e., file
»  17 descriptor 0 for
SVR4 UNIX - uses full duplex pipes (read/write on both file descriptors) »  {atlas:maria:197} input, and 1 for
Maria Hybinette, UGA 3 Maria Hybinette, UGA output. 4

{atlas:maria:195} who > tmpfile


{atlas:maria:196} wc -l < tmpfile
17 Programming with Pipes
{atlas:maria:197} who | wc -l
Hello Gunnar!
17 Process Process
Chat Chat
{atlas:maria:197} cat tmpfile Maria Gunnar
A B
luffman pts/44 Apr 26 10:17 (h198-137-28-67.paws.uga.edu) #include <unistd.h>
Hi Nice to Hear
imacs pts/25 Apr 26 08:43 (128.192.4.35) from you!
int pipe( int fd[2] );
cai pts/38 Apr 26 09:15 (user-1121m0h.dsl.mindspring.com)
maher
luffman
pts/20
pts/50
Apr 26 04:57
Apr 26 09:52
(adsl-219-4-207.asm.bellsouth.net)
(h198-137-28-67.paws.uga.edu)
●  pipe()binds fd[]with two file descriptors:
moore pts/55 Apr 26 10:43 (adsl-219-226-14.asm.bellsouth.net) »  fd[0] used to read from pipe (consumer)
tanner pts/117 Apr 26 08:46 (cmtspool-48.monroeaccess.net)
weaver pts/106 Apr 26 08:12 (creswell-s218h112.resnet.uga.edu) »  fd[1] used to write to pipe (producer)
dimitrov pts/39 Apr 26 09:01 (128.192.42.142)
steward pts/23 Apr 26 09:16 (128.192.101.7) ●  Returns 0 if OK and -1 on error. User process

weaver pts/12 Apr 26 08:14 (creswell-s218h112.resnet.uga.edu)


dme pts/6 Apr 25 09:34 (128.192.4.136) ●  Example error: fd[0] fd[1]
ldeligia pts/40 Apr 26 10:10 (128.192.4.72)
»  too many fd open already.
brownlow pts/13 Apr 26 09:48 (68-117-218-71.dhcp.athn.ga.charter.com)
misztal pts/30 Mar 27 10:32 (kat.cs.uga.edu)
pipe
james pts/51 Apr 26 09:28 (adsl-35-8-252.asm.bellsouth.net)
cs4720 pts/107 Mar 27 15:06 (druid)
Kernel

Maria Hybinette, UGA 6


Example: Pipe within a single
process Example: pipe-yourself.c
write( p[1], msg1, MSGSIZE );
#include <stdio.h> write( p[1], msg2, MSGSIZE );
●  Simple example: #include <unistd.h> write( p[1], msg3, MSGSIZE );
#define MSGSIZE 16 /* null */
»  creates a pipe called p for( i=0; i < 3; i++ )
char *msg1= hello, world #1 ; { /* read pipe */
»  writes three messages to the pipe (down the pipe) read( p[0], inbuf, MSGSIZE );
char *msg2= hello, world #2 ; printf( %s\n , inbuf );
»  reads (receives) messages from the pipe char *msg3= hello, world #3 ; }
return 0; {saffron:ingrid:4} pipe-yourself
int main() } hello, world #1
{
●  Process (user) view: char inbuf[MSGSIZE];
hello, world #2
hello, world #3
pipe p int p[2], i;

p[0] (read) if( pipe( p ) < 0 ) pipe p


process { /* open pipe */
p[1] (write) perror( pipe ); p[0] (read)
exit( 1 );
}
process
p[1] (write)

Maria Hybinette, UGA 7 Maria Hybinette, UGA 8

Example: Pipe between a parent


Things to Note and child
●  Pipes uses FIFO ordering: first-in first-out.
»  messages are read in the order in which they were 1.  Creates a pipe
written.
2.  Creates a new process via fork()
»  lseek() does not work on pipes.
3.  Parent writes to the pipe (fd 1)
●  Read / write amounts do not need to be the
same, but then text will be split differently. 4.  Child reads from pipe (fd 0)
●  Pipes are most useful with fork() which
creates an IPC connection between the parent
and the child (or between the parents children)

parent
parent Pipe child

child Pipe child


Maria Hybinette, UGA 9 Maria Hybinette, UGA 10

Example: pipe-fork.c Things to Note


if( pid > 0 ) /* parent */
#include <stdio.h> {
#include <sys/wait.h> write( p[1], msg1, MSGSIZE );
#include <unistd.h> write( p[1], msg2, MSGSIZE ); ●  Pipes are intended to be unidirectional
#define MSGSIZE 16 write( p[1], msg3, MSGSIZE );
wait( (int *) 0 );
channels if parent-child processes both read
char *msg1= hello, world #1 ; } if( pid == 0 ) /* child */
{
and write on the pipe at the same time
char *msg2= hello, world #2 ;
char *msg3= hello, world #3 ; for( i=0; i < 3; i++ ) confusion.
{
int main()
{
read( p[0], inbuf, MSGSIZE );
printf( %s\n , inbuf );
●  Best style is for a process to close the links it
char inbuf[MSGSIZE];
int p[2], i, pid; }
}
return 0;
does not need. Also avoids problems
if( pipe( p ) < 0 )
} (forthcoming).
{ /* open pipe */ p[0] (read) p[0] (read)
perror( pipe );
exit( 1 );
}
if( (pid = fork()) < 0 ) parent child parent child
{
perror( fork );
exit( 2 ); p[1] (write) p[1] (write)
}
Maria Hybinette, UGA 11 Maria Hybinette, UGA 12
Example: pipe-fork-close.c Some Rules of Pipes
if( pid > 0 ) /* parent */
#include <stdio.h> { ●  Every pipe has a size limit
#include <sys/wait.h> close( p[0] ); /* read link */
#include <unistd.h> write( p[1], msg1, MSGSIZE );
»  POSIX minimum is 512 bytes -- most systems makes this figure
#define MSGSIZE 16 write( p[1], msg2, MSGSIZE ); larger
write( p[1], msg3, MSGSIZE );
char *msg1= hello, world #1 ; wait( (int *) 0 ); if( pid == 0 ) /* child */
char *msg2= hello, world #2 ; } { ●  read() blocks if pipe is empty and there is a a write link open to
char *msg3= hello, world #3 ; close( p[1] ); /* write link */ that pipe [it hangs]
for( i=0; i < 3; i++ )
int main()
{ { ●  read() from a pipe whose write() end is closed and is empty
char inbuf[MSGSIZE]; read( p[0], inbuf, MSGSIZE ); returns 0 (indicates EOF) [but it doesn’t hang]
int p[2], i, pid; printf( %s\n , inbuf );
} »  Lesson Learned: Close write links o/w read() will never return ***
if( pipe( p ) < 0 ) } return 0;
{ /* open pipe */ }
perror( pipe ); ●  write() to a pipe with no read() ends returns -1 and generates
exit( 1 );
}
p[0] (read) SIGPIPE and errno is set to EPIPE
if( ( pid = fork() ) < 0 ) ●  write() blocks if the pipe is full or there is not enough room to
{
perror( fork );
parent child support the write().
exit( 2 ); »  May block in the middle of a write()
}
Maria Hybinette, UGA p[1] (write) 13 Maria Hybinette, UGA 14

Example: Several Writers

●  Perfectly possible to have multiple ●  Since a write() can suspend in the middle of
readers / writers attached to a pipe its output then output from multiple writers
»  can cause confusion output may be mixed up (or interleaved).

writer
maria was great…

writer big tree…


maria is getting big…

reader
writer
…is getting a pizza…

Maria Hybinette, UGA 15 Maria Hybinette, UGA 16


pipe-nonblocking.c

Avoid Interleaving Non-blocking read() & write()

●  In limits.h, the constant PIPE_BUF gives ●  Problem: Sometimes you want to avoid
the maximum number of bytes that can be read()and write()from blocking.
output by a write()call without any chance
of interleaving. ●  Goals:
»  want to return an error instead
●  Use PIPE_BUF is there are to be multiple »  want to poll several pipes in turn until one has data
writers in your code.
●  Approaches:
»  Use fstat()on the pipe to get #characters in pipe
(caveat: multiple readers may give a “race
condition”)
»  Use fcntl() on the pipe and set it to O_NONBLOCK

Maria Hybinette, UGA 17


pipe-nonblocking.c Maria Hybinette, UGA 18
pipe-nonblocking.c
Using fcntl() Example: Non-blocking with -1 return
#include <sys/types.h>
#include <unistd.h> ●  Parent “launches’ one child
#include <fcntl.h>
: .
●  Child writes hello to parent every 3 seconds (3
if( fcntl( fd, F_SETFL, O_NONBLOCK ) < 0 ) times).
perror( fcntl );
: ●  Parent read what the child writes
●  Parent does a non-blocking read each second.
●  Non-blocking write: On a write-only file descriptor, fd,
future writes will never block ●  Child does blocking write – … there nothing else
»  Instead return immediately with a -1 and set errno to EAGAIN to do than write.
●  Non-blocking read: On a read-only file descriptor, fd,
hello
future reads will never block p[0] (read)
hello
»  return -1 and set errno to EAGAIN unless a flag is set to
O_NDELAY then return 0 if pipe is empty (or closed) child hello parent

19 p[1] (write) 20
Maria Hybinette, UGA pipe-nonblocking.c Maria Hybinette, UGA pipe-nonblocking.c

Example: Non-blocking with -1 return Example: pipe-nonblocking.c


#include <unistd.h> if( fcntl( pfd[0], F_SETFL, O_NONBLOCK ) < 0 )
●  Parent’s behavior à #include <fcntl.h> { /* read non-blocking */
»  Need to check for ●  Child’s behavior à #include <errno.h> perror( fcntl );
exit( 2 );
–  No data in pipe »  Just writes and #define MSGSIZE 6 }
–  Pipe is closed blocks if the pipe is char *msg1= hello ; switch( fork() )
(EOF) full {
void parent_read( int p[] ); case -1: /* error */
–  Errors (in general)
void child_write( int p[] ); perror( fork );
»  Continuously Read exit(3);

int main() case 0: /* child */


child_write( pfd );
{
break;
int pfd[2];
hello p[0] (read) default: /* parent */
if( pipe( pfd ) < 0 )
hello parent_read( pfd );
{ /* open pipe */
break;
child hello parent perror( pipe );
}
exit( 1 );
return 0;
}
p[1] (write) }

Maria Hybinette, UGA 21


pipe-nonblocking.c Maria Hybinette, UGA 22
pipe-nonblocking.c

void parent_read() void child_write()


void parent_read( int p[] ) void child_write( int p[] )
{ {
int nread; int i;
else
char buf[MSGSIZE]; close( p[0] ); /* read link */
{ {saffron} pipe-nonblocking
close( p[1] ); /* write link */
perror( read ); for( i = 0; i < 3; i++ )
while( 1 ) (pipe is empty)
exit(4 ) {
{ MSG=hello
nread = read( p[0], buf, MSGSIZE ); } write( p[1], msg1, MSGSIZE );
(pipe is empty)
switch( nread ) sleep( 3 );
case 0: (pipe is empty)
{ }
/* pipe has been closed */ (pipe is empty)
case -1: close( p[1] ); /* write link */
printf( "End conversation\n" ); MSG=hello
if( errno == EAGAIN )
close( p[0] ); /* read fd */ }
{ (pipe is empty)
printf( (pipe empty)\n ); exit(0); (pipe is empty)
sleep( 1 ); default: /* text read */ MSG=hello
break; printf( "MSG=%s\n", buf ); (pipe is empty)
} } /* switch */ (pipe is empty)
EAGAIN: No data in
} /* while */ (pipe is empty)
pipe (yet) try
} /* parent_read */ End of conversation
AGAIN later
Maria Hybinette, UGA 23 Maria Hybinette, UGA 24
Non-blocking with 0 error Review, and reflect

●  If non-blocking read()does not distinguish ●  We created a pipe in a single process, and


between end-of-input and an empty pipe (e.g. communicated via the pipe (pipe-yourself.c)
O_NDELAY is set ) then can use special »  Not pragmatic
message to mean end: ●  We created a pipe between [a] child(ren) and
»  e.g. send bye as last message a parent
»  Interesting! Spoon?

»  Lets look more deeply into what happens after


fork?

Maria Hybinette, UGA 25 Maria Hybinette, UGA 26

What Happens After Fork? Some Pipe Rules


User Process (Parent) User Process (Child)
User Process (Parent)
●  A forked child
fd[0] fd[0] fd[0]
fd[1] fd[1] »  Inherits file descriptors from its parent
fd[1]
●  pipe()
»  Creates an
Pipe –  internal system buffer and
Pipe
–  2 file descriptors:
●  one for reading and one for writing.
Before Fork After Fork
●  After the pipe call,
»  The parent and child should close the file
●  Design Question: descriptors for the opposite direction (that it
»  Need to decide on : doesn’t need).
–  The direction of the data flow – then close »  Leaving them open does not permit full-duplex
appropriate ends of pipe (at both parent and child) communication.
Maria Hybinette, UGA 27 Maria Hybinette, UGA 28

Manipulating File Descriptors:


Pipes and exec() dup2
Motivation: How can we code who | sort ?
#include <unistd.h>
int dup2( int old-fd, int new-fd );
Observation: Writes to stdout and reads from stdin.
1.  Use exec() to ‘run’ code in two different child ●  Sets one file descriptor to the value of
new-fd
another.,
processes old fd
»  Existing file descriptor, old-fd, is
»  one runs who [child2] and the other sort [child1] duplicated onto new-fd so that they refer to
»  exec in child(ren) starts a new program within their copy the same file
File
of the parent process ●  If new-fd already exists, it will be closed
first.
2.  Connect the pipe to stdin and stdout using
dup2().
Example:
»  dup2( fd[1], fileno(stdout));
Pipeline.c
Maria Hybinette, UGA 29 Maria Hybinette, UGA 30
Connecting pipes with stdin &
stdout Four Stages to who | sort

●  Connect the write end of a 1.  main() creates a pipe


pipe to stdout
»  int p[2];
pipe( p );
dup2( p[1], STDOUT_FILENO );
●  Connect the read end of pipe p[0] (read)
to stdin
p[0] (read) main
»  dup2( p[0], STDIN_FILENO );

p[1] (write)
stdin
p[1] (write)
Caveat: Beware of hanging on the stdout int fds[2];
‘pipe’ pipe( fds ) ; /* no error checks */
Solution: Close all file descriptors
that comprise its pipes so that the
pipes
Maria Hybinette, UGA don't hang. 31 Maria Hybinette, UGA 32

Four Stages to who | sort Four Stages to who | sort

1.  main() creates a pipe 1.  main() creates a pipe


2.  main() forks twice to 2.  main() forks twice to
dup2( p[0] , STDIN_FILENO );
make two children that make two children and
inherits the pipes inherits the pipes
descriptors p[0] (read) sort descriptors p[0] (read) sort

3.  Child: Couple standard


main output to write end main

who
4.  Child: Couple standard who
p[1] (write) input to read end p[1] (write)
5.  Close the pipe links
See code… whosort.c which are not needed
dup2( p[1] , STDOUT_FILENO );

Maria Hybinette, UGA 33 Maria Hybinette, UGA 34

Four Stages to ps | sort who | sort :whosort.c


#include <sys/types.h> if( fork() == 0 )
#include <unistd.h> { /* 2nd child */
1.  main() creates a pipe #include <fcntl.h> /* who --> fds[1]/stdout --> sort */
#include <sys/wait.h> dup2( p[1] , STDOUT_FILENO );
2.  main() forks twice to close( p[ 0 ] );

make two children and int main()


{
execlp( "who", "who", (char *) 0 );
}
inherits the pipes int p[2]; else
descriptors p[0] (read) sort1
Child
pipe( p ); /* no error checks */ { /* parent closes all links */
close( p[ 0 ] );
3.  Close the pipe links if( fork() == 0 ) close( p[ 1 ] );
which are not needed main { /* 1st child */
/* fds[0]/stdin --> sort */ wait( (int *) 0 );
4.  Replace children by dup2( p[0] , STDIN_FILENO ); wait( (int *) 0 );
who 2
Child close( p[ 1 ] ); } /* else parent second child */
programs using p[1] (write) execlp( "sort", "sort", (char *) } /* else parent first child */
exec() 0 ); return 0;
} }
else
{atlas:maria:169} who-sort
{ /* parent - create another kid */
aguda dtremote Apr 25 15:46 (128.192.101.83:0)
ananda pts/25 Apr 25 10:52 (128.192.4.101)
anyanwu pts/24 Apr 25 11:30 (dhcp183)
bralley dtremote Apr 25 15:38 (128.192.101.84:0)
Maria Hybinette, UGA 35 Maria Hybinette, UGA 36
Limitations of Pipes Something more interesting…

●  Processes using a pipe must come from a


common ancestor: ●  Example : sort < file1.txt | uniq
»  e.g. parent and child
»  cannot create general servers like print spoolers or ●  What does this look like? How would a shell
network control servers since unrelated processes
cannot use it be programmed to process this?
»  Well we know we need a parent & child to
●  Pipes are not permanent
communicate though the pipe!
»  they disappear when the process terminates
»  Parent
●  Pipes are one-way:
»  Child
»  makes fancy communication harder to code
»  We need to open a file and read from it – and then
●  Readers and writers do not know each other. read it as we read it from standard input.
●  Pipes do not work over a network
Maria Hybinette, UGA 37 Maria Hybinette, UGA 38

Want: sort < file1.txt | uniq Want: sort < file1 | uniq

Parent uniq Child sort Parent


filedes
stdin fd[0] stdin fd[0] stdin fd[0]
stdout fd[1] stdout fd[1] stdout fd[1]

file1.txt File
file1.txt
1
Pipe

●  Want: How do we get there? fileDES = open( file1.txt", O_RDONLY );

Step 1: We want to read from the file Step 2: Read from the file like it is from stdin
Maria Hybinette, UGA 39 Maria Hybinette, UGA 40

Want: sort < file1 | uniq Want: sort < file1 | uniq

Parent Parent
filedes filedes
stdin fd[0] stdin fd[0]
stdout fd[1] stdout fd[1]

File
file1.txt File
file1.txt
1 1

fileDES = open( ”file1.txt", O_RDONLY ); fileDES = open( ”file1.txt", O_RDONLY );


dup2( fileDES, fileno( stdin ) ); dup2( fileDES, fileno( stdin) );
Step 3: Don’t need fileDES anymore …
41
close( fileDES ); Step 4: Hairier – now we deal with the pipe…
42
Maria Hybinette, UGA Maria Hybinette, UGA
Want: sort < file1 | uniq

Parent
filedes ●  No : Not really that bad
stdin fd[0] »  Just need to create the pipe then create a child (or
stdout fd[1]
parent) that is on the other side of the pipe!
–  Then do the plumbing:
●  Reroute stdin/stdout appropriately….
File
file1.txt
1
Pipe ●  AND THAT IS IT!
UGH Hairy!

pipe( fd );
… fork() …

Maria Hybinette, UGA 43 Maria Hybinette, UGA 44

Want: sort < file1 | uniq Want: sort < file1 | uniq

Parent Child Parent uniq Child sort


filedes filedes
stdin fd[0] stdin fd[0] stdin fd[0] stdin fd[0]
stdout fd[1] stdout fd[1] stdout fd[1] stdout fd[1]

File
file1.txt File
file1.txt
1 1
Pipe Pipe

fork(); fork();
/* now do the plumbing */ /* decide who does what (arbitrary) */

Maria Hybinette, UGA 45 Maria Hybinette, UGA 46

Want: sort < file1 | uniq Want: sort < file1 | uniq

Parent uniq Child sort Parent uniq Child sort


filedes filedes
stdin fd[0] stdin fd[0] stdin fd[0] stdin fd[0]
stdout fd[1] stdout fd[1] stdout fd[1] stdout fd[1]

File
file1.txt File
file1.txt
1 1
Pipe Pipe

/* make writing to the pipe the same


close(fd[0]); close(fd[1]); /* child */
/* as writing to stdout */
/* leaving the ---- connections for child */
dup2( fd[1], fileno(stdout)); /* in green */
Maria Hybinette, UGA 47 Maria Hybinette, UGA 48
Want: sort < file1 | uniq Want: sort < file1 | uniq

Parent uniq Child sort Parent uniq Child sort


filedes filedes
stdin fd[0] stdin fd[0] stdin fd[0] stdin fd[0]
stdout fd[1] stdout fd[1] stdout fd[1] stdout fd[1]

File
file1.txt File
file1.txt
1 1
Pipe Pipe

dup2(fd[0], fileno(stdin)); /* parent */ close(fd[1]); close(fd[0]); /* parent */


/* parent reads from pipe */

Maria Hybinette, UGA 49 Maria Hybinette, UGA 50

Example : sort < file1 | uniq Thought questions


# include <stdio.h> pid = fork();
# include <stdlib.h> if( pid < 0 )
# include <unistd.h> {
# include <fcntl.h> perror("fork"); ●  Other ways of designing this task?
exit(1);
/* child | parent */ } ●  Is this the only way?
/* sort < file1.txt | uniq */ else if( pid == 0 ) // child
int main() {
{ close( pipeDES[0] );
int status; dup2( pipeDES[1], fileno(stdout) );
int fileDES; close( pipeDES[1]);
int pipeDES[2]; execl( "/usr/bin/sort", "sort", (char *) 0 );
pid_t pid; } End of Tutorial
else if( pid > 0 ) // parent
fileDES = open( "myfile.txt", O_RDONLY ); {
dup2( fileDES, fileno( stdin) ); close( pipeDES[1] );
dup2( pipeDES[0], fileno(stdin) );
/* don't need to read via this one anymore */ close( pipeDES[0]);
close( fileDES ) ; execl( "/usr/bin/uniq", "uniq", (char *) 0 );
}
/* create a child that communicate via a pipe */ }
/* parent reads from pipe, child writes to pipe */
pipe( pipeDES );
Maria Hybinette, UGA 51 Maria Hybinette, UGA 52

What are FIFOs/Named Pipes? Creating a FIFO


Default mode is the
●  Similar to pipes (as far as read/write are ●  UNIX mkfifo command: difference: 0666 -
concerned, e.g. FIFO channels), but with some $ mkfifo fifo1 umask value
additional advantages:
§  Unrelated processes can use a FIFO. ●  On older UNIXs (origin ATT UNIX), use mknod:
§  A FIFO can be created separately from the processes $ mknod fifo1 p p means FIFO
that will use it.
§  FIFOs look like files: ●  Use ls to get information:
•  have an owner, size, access permissions
$ ls -l fifo1
•  open, close, delete like any other file prw-rw-r-- 1 maria maria 0 Oct 23 11.45 fifo1|
•  permanent until deleted with rm

Maria Hybinette, UGA 53 Maria Hybinette, UGA 54


Using FIFOs: FIFO Blocking Reader / Writer Example
fifo1
read
$ cat < fifo1 &
●  FIFOs can be read and written using write cat
[1] 22341
standard UNIX commands connected via $ ls -l > fifo1; wait ls -l
< and > standard input or output total 17
prw-rw-r-- 1 maria usr 0 Oct 23 11.45 fifo1 :
[1] + Done cat < fifo1
●  If there are no writers then a read: $
e.g. cat < fifo1
will block until there is 1 or more writers. 1.  Output of ls -l is written down the FIFO
2.  Waiting cat reads from the FIFO and display the output
3.  cat exits since read returns 0 (the FIFO is not open for writing
●  If there are no readers then a write: anymore and 0 is returned as EOF)
e.g. ls -l > fifo1
will block until there is 1 or more readers.
wait - causes the shell to wait until cat exits before redisplaying the prompt.

Maria Hybinette, UGA 55 Maria Hybinette, UGA 56

Outline on how to program with


Creating a FIFO in C FIFOs

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


#include <sys/stat.h>
#include <sys/stat.h>
#include <fcntl.h>

int mkfifo( const char *pathname, mode_t mode );


#define MSGSIZE 63

●  Returns 0 if OK, -1 on error. int main()


●  mode is the same as for open() - and is modifiable by the {
process umask value int fd;
char msgbuf[MSGSIZE+1];
●  Once created, a FIFO must be opened using open()
mkfifo( /tmp/mariafifo , 0666 );
Note: the significant difference between programming with fd = open( /tmp/mariafifo , O_WRONLY );
.
pipes versus FIFOs is initialization.
.
}

Maria Hybinette, UGA 57 Maria Hybinette, UGA 58

Two Main Uses of FIFOs Shell Usage

1.  Used by shell commands to pass data ●  Example: Process a filtered output stream
from one shell pipeline to another twice – i.e., pass filtered data to two separate
processes:
without using temporary files.
filtered
prog3
data
2.  Create client-server applications on a input file prog1
single machine.
prog2

●  In contrast to regular pipes, FIFOs allows


non-linear connections between processes
such as the above, since FIFO s are pipes
with names.
Maria Hybinette, UGA 59 Maria Hybinette, UGA 60
filtered
prog3
data

input file prog1

Implementation prog2
A Client-Server Application
UNIX s tee() copies standard input to both its
~ standard input and to the ●  Server contacted by numerous clients via a
well-known FIFO
~ file named on its command line
prog3 well-known
client FIFO
filtered
data read requests
Server
input file prog1 tee
client
prog2

●  How are replies from the server sent back to


$ mkfifo fifo1
$ prog3 < fifo1 & each client?
$ prog1 < infile | tee fifo1 | prog2
Maria Hybinette, UGA 61 Maria Hybinette, UGA 62

Client-Server FIFO Application Problems


●  Problem: A single FIFO (as before) is not enough.
●  Solution: Each client send its PID as part of its ●  The server does not know if a client is still
message. Which the uses to create a speciaal alive
reply FIFO for each client »  may create FIFOs which are never used
»  e.g. /tmp/serv1.XXXX where XXXX is replaced with the »  client terminates before reading the response
clients process ID (leaving FIFO w/ one writer and no reader)
client-specific FIFO
es
read repli
client ●  Each time number of clients goes from 1 client
well-known FIFO
to 0 the clients server reads 0 /EOF on the
read requests
Server
well-known FIFO, if it is set to read-only.
»  Common trick is to have the server open the FIFO as
client read-write (see text book for more details)
read repl
ies

Maria Hybinette, UGA 63 Maria Hybinette, UGA 64

Programming Client-server
Applications Opening FIFOs

#include <sys/types.h>
●  First we must see how to open and read a FIFO #include <sys/stat.h>
from within C.
#include <fcntl.h>
:
●  Clients will write in non-blocking mode, so they fd = open( fifo1 , O_WRONLY );
do not have to wait for the server process to :
start. ●  A FIFO can be opened with open() (most I/O
functions work with pipes).

Maria Hybinette, UGA 65 Maria Hybinette, UGA 66


Blocking open() Non-blocking open()

●  An open()call for writing will block until another if ( fd = open( fifo1 , O_WRONLY | O_NONBLOCK)) < 0 )
perror( open FIFO );
process opens the FIFO for reading.
»  this behavior is not suitable for a client who does not
want to wait for a server process before sending data. ●  opens the FIFO for writing
●  returns -1 and errno is set to ENXIO if there are no
●  An open()call for reading will block until another readers, instead of blocking.
process opens the FIFO for writing.
●  Later write()calls will also not block.
»  this behavior is not suitable for a server which wants to
poll the FIFO and continue if there are no readers at the
moment.

Maria Hybinette, UGA 67 Maria Hybinette, UGA 68

Example: send-msg, recv-msg Some Points

●  recv-msg can read and write;


●  opens the FIFO for writing »  otherwise the program would block at the open call and
●  returns -1 and errno is set to ENXIO if there are no »  avoids responding to reading a return of 0 when the
number of send-msg processes goes from 1 to 0 (and the
readers, instead of blocking. FIFO is empty) O_RDWR - ensures that at least one process
has the FIFO open for writing (i.e. recv-msg itself) so read
●  Later write()calls will also not block. will always block until data is written to the FIFO

hello…
●  send-msg sends fixed-size messages of length PIPE_BUF
send-msg well-known to avoid interleaving problems with other send-msg calls.
tomato FIFO: serv-fifo It uses non-blocking.
recv-msg
●  serv_fifo is globally known, and previously created
with mkfifo
send-msg
labradoodle
Maria Hybinette, UGA 69 Maria Hybinette, UGA 70

send-msg.c & recv-msg.c send-msg.c


int main( int argc, char *argv[] )
{
#include <stdio.h> int fd, i; /* put input message into mb[] with '$'
{saffron:ingrid:3} recv-msg * and padded with spaces */
#include <sys/types.h> char msgbuf[PIPE_BUF];
serv_fifo: No such file or directory void make_msg( char mb[], char
#include <sys/stat.h>
{saffron:ingrid:4} mkfifo serv_fifo if( argc < 2 ) input[] )
#include <unistd.h>
{saffron:ingrid:5} recv-msg & { {
#include <fcntl.h>
[1] 792 printf( "Usage: send-msg msg...\n" ); int i;
#include <string.h> exit( 1 ); for( i = 1; i < PIPE_BUF-1; i++ )
Msg: hi
#include <limits.h> } mb[i] = ' ';
Msg: potato
if( (fd = open( SF, O_WRONLY | O_NONBLOCK )) < 0) mb[i] = '\0';
Msg: pizza { perror( SF ); exit( 1 ); }
#define SF "serv_fifo" i = 0;
for( i = 1; i < argc; i++ )
while( input[i] != 0 )
{
{
if( strlen( argv[i] ) > PIPE_BUF - 2 )
mb[i] = input[i];
{saffron:ingrid:3} send-msg "hi" potato..." & printf( "Too long: %s\n", argv[i] );
i++;
else
[1] 794 }
{
{saffron:ingrid:4} send-msg pizza" & make_msg( msgbuf, argv[i] ); mb[i] = '$';
[2] 795 write( fd, msgbuf, PIPE_BUF ); } /* make_msg */
[1] - Done send-msg hi potato }
}
[2] - Done send-msg pizza close( fd );
return 0;
Maria Hybinette, UGA 71 Maria Hybinette, UGA } /* end main */ 72
recv-msg.c Things to Note about recv-msg
int main( int argc, char *argv[] )
{
int fd, i; ●  open()is blocking, so read()calls will block
char msgbuf[PIPE_BUF];
when the pipe is empty
/* print mb[] up to the '$' marker */
if( (fd = open( SF, O_RDWR )) < 0 )
void print_msg( char mb[] )
{
{
perror( SF );
exit( 1 );
int i = 0; ●  open() uses O_RDWR not O_RDONLY
printf( "Msg: " );
}
while( mb[i] != '$' )
»  this means there is a write link to the FIFO even
while( 1 )
{ { when there are no send-msg processes
if( read( fd, msgbuf, PIPE_BUF ) < 0 ) putchar( mb[i] );
{ i++;
perror( "read" ); } »  this means that a read()call will block even when
exit( 1 ); putchar( '\n' ); there are no send-msg processes, instead of
}
print_msg( msgbuf );
} /* make_msg */ returning 0.
}
close( fd );
return 0;
} /* end main */

Maria Hybinette, UGA 73 Maria Hybinette, UGA 74

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy