# Ch15 Interprocess Communication
>###### tags: `APUE`
### Pipe
Pipes are the oldest form of UNIX IPC with two limitations:
1. half duplex
2. It can be used only betwwen processes that have a common ancestor
```c =
#include <unistd.h>
int pipe(int filedes[2]);
//filedes [0] :open for reading
//filedes [1] :open for writing
```
### Pipe1
Two ends of a pipe connected in a single process.
```c=
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char* argv[]){
int pipefd[2];
char* str = "hello\n\0";
char buffer[100];
pipe(pipefd);
write(pipefd[1],str,strlen(str)+1);
read(pipefd[0],buffer,200);
printf("%s\n",buffer);
return 0;
}
```
### Pipe2
Fork after pipe,the child inherits a copy of the file descriptor. So closing the descriptor in the child will close it for the child, but not the parent, and vice versa.
Here is the example for communication between a parent process and a child process.
```c=
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
int main(int argc,char* argv[]){
int pipefd[2];
char* str = "hello my child\n";
char buffer[100];
int ret;
pipe(pipefd);
ret = fork();
assert(ret >= 0);
if (ret > 0){
printf("parent\n");
close(pipefd[0]); //parent close its read end
write(pipefd[1],str,strlen(str)+1);
}
else{
printf("child\n");
close(pipefd[1]); //child close its write end
read(pipefd[0],buffer,100);
printf("%s",buffer);
}
return 0;
}
```
### Pipe3
Call dup after closing stdin or stdout to redirect them to pipe.
The new file descriptor returned by dup() is the lowest-numbered available file descriptor.
```c=
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
int main(int argc,char* argv[]){
int pipefd[2];
char buffer[200];
int ret;
pipe(pipefd);
ret = fork ();
assert(ret >= 0);
if (ret == 0){ //child
close(1); //close stdout
dup(pipefd[1]);
close(pipefd[0]);
printf("hello\n");
}
else{ //parent
close(0);
dup(pipefd[0]);
close(pipefd[1]);
scanf("%s",buffer);
printf("parent:%s\n",buffer);
}
return 0;
}
```
### Pipe3-1
Compared with Pipe3, Pipe3-1 use fgets to replace scanf.The most important thing is we shall always remember close the unused pipe fd.
```c=
FILE* in_stream;
if(ret == 0){ //parent
close(1);
dup(pipefd[1]);
printf("spoiled brat\n");
close(pipefd[0]);
close(pipefd[1]);
}
else{ //child
close(0);
dup(pipefd[0]);
in_stream = fdopen(0,"r");
fgets(buffer,100,in_stream);
printf("from parent:%s",buffer);
close(pipefd[0]);
close(pipefd[1]);
}
```
### Pipe4
Finally, we write a program to implement the command "ls | wc" with fork-exec mechanism.
```c=
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc,char* argv[])
{
int pipefd[2];
int pid1,pid2,wstat;;
pipe(pipefd);
pid1 = fork();
assert(pid1 >= 0);
if(pid1 == 0){ //parent
printf("I am parent\n");
close(pipefd[0]);
close(pipefd[1]);
wait(&wstat);
}
else{
printf("I am child1\n");
pid2 = fork();
assert(pid2 >= 0);
if(pid2 > 0){
printf("I am child2\n");
close(0); //close stdin
dup(pipefd[0]); //read end
close(pipefd[0]);
close(pipefd[1]);
execlp("/usr/bin/wc","wc",NULL);
}
close(1); //close stdout
dup(pipefd[1]); //write end
close(pipefd[0]);
close(pipefd[1]);
execlp("/bin/ls","ls",NULL);
}
return 0;
}
```