Pipes, Part 1: Introduction to pipes - tcloaa/SystemProgramming GitHub Wiki
- A POSIX pipe is just like a "real pipe" - you can push bytes into one end and they will appear at the other end in the same order.
- However, unlike real pipes, the flow of flow is always in the same direction (while for real pipe, water can flow in both directions!).
- One file descriptor is used for reading and the other for writing. The system call
pipe
is used to create a pipe.
//classic pattern, always a pair of int, and then pipe() it
int filedes[2];
pipe (filedes);
//You must read from fd[0] and write from fd[1]
printf("read from %d, write to %d\n", filedes[0], filedes[1]);
These file descriptors can be used with
write
往管子fd[1]
里写:
write(filedes[1], "Go!", 4);
And read
从管子fd[0]
里接受:
char buffer[80];
int bytesread = read(filedes[0], buffer, sizeof(buffer));
//then do something with the received:
A common method of using pipes is to create the pipe before forking your parent process
.
###Example 1
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
int filedes[2];
pipe (filedes);
pid_t child = fork();
if (child > 0) { /* I am the parent */
char buffer[80];
int bytesread = read(filedes[0], buffer, sizeof(buffer));
// do something with the bytes read
}
//The child can then send a message back to the parent:
if (child == 0) {
write(filedes[1], "done", 4);
}
}
###Example 2
If the parent wants to receive data from the child, it should close fd1, and the child should close fd0.
If the parent wants to send data to the child, it should close fd0, and the child should close fd1.
Since descriptors are shared between the parent and child, we should always be sure to close the end of pipe we aren't concerned with.
On a technical note, the EOF will never be returned if the unnecessary ends of the pipe are not explicitly closed.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string)+1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
}
return(0);
}
Yes, but it is meaningless!
Here's an example program that sends a message to itself:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int fh[2];
pipe(fh);
FILE *reader = fdopen(fh[0], "r");
FILE *writer = fdopen(fh[1], "w");
// Hurrah now I can use printf rather than using low-level read() write()
printf("Writing...\n");
fprintf(writer,"%d %d %d\n", 10, 20, 30);
fflush(writer);
printf("Reading...\n");
int results[3];
int ok = fscanf(reader,"%d %d %d", results, results + 1, results + 2);
printf("%d values parsed: %d %d %d\n", ok, results[0], results[1], results[2]);
return 0;
}
Problem: Block
Problem with using a pipe in this fashion:
Since the pipe only has a limited buffering capacity (say real pipe has finite length!), if the pipe is full, then the writing process will block!
The max size of the buffer is system-dependent; typical values from 4KB upto 128KB.
Example:
int main() {
int fh[2];
pipe(fh);
int b = 0;
#define MESG "..............................."
while(1) {
printf("%d\n",b);
write(fh[1], MESG, sizeof(MESG))
b+=sizeof(MESG);
}
return 0;
}