02 CPipeShell
02 CPipeShell
● What is a pipe?
CSCI 4730/6730 ● UNIX System review
Systems Programming Refresher ● Processes (review)
● Pipes
● FIFOs
Pipes & FIFOs
● 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
parent
parent Pipe child
● 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…
reader
writer
…is getting a pizza…
● 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
19 p[1] (write) 20
Maria Hybinette, UGA pipe-nonblocking.c Maria Hybinette, UGA pipe-nonblocking.c
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
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 );
Want: sort < file1.txt | uniq Want: sort < file1 | uniq
file1.txt File
file1.txt
1
Pipe
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
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() …
Want: sort < file1 | uniq Want: sort < file1 | uniq
File
file1.txt File
file1.txt
1 1
Pipe Pipe
fork(); fork();
/* now do the plumbing */ /* decide who does what (arbitrary) */
Want: sort < file1 | uniq Want: sort < file1 | uniq
File
file1.txt File
file1.txt
1 1
Pipe Pipe
File
file1.txt File
file1.txt
1 1
Pipe Pipe
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
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
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).
● 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.
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