1.进程间通信的方式:
(1)管道:一种两个进程间进行单向通信的机制,半双工的通信方式。数据只能单方向流动,而且只能在具有亲缘关系(父子进程、兄弟进程)的进程间使用。
从通信的双方信息交互的方式分三种基本模式:
单工通信(单向通信) 只有一个方向的通信而没有反方向的交互(信息流是单方向的),发送端和接收端的身份是固定的;
半双工通信(双向交替通信)双方均可以发送、接收信息,但是同一时刻里,信息只能有一个传输方向;
全双工通信(双向同时通信) 双方可以同时发送和接收信息。
(2)有名管道:(FIFO)半双工的通信方式,克服了只能有亲缘关系的进程通信的限制。
(3)信号量;4)消息队列;(5)信号(chapter 9);(6)共享内存;7)套接字。
2.管道的概念
管道:两个进程间进行单向通信的机制(半双工管道)
局限性:由于管道传递数据的单向性,决定其使用的局限性:数据的单向流动;有亲缘关系的进程间的通信;没有名字;缓冲区大小受限制(传送的是无格式的字节流)
管道就是一个存在于内存的特殊文件,进程就是通过读写该文件进行通信的(内存中的某个页面作为数据缓冲区)
如果要建立两个进程的数据通路,首先父进程应调用pipe创建管道,接着调用fork,由于子进程自动继承父进程的数据段,便可实现父子进程同时拥有管道的操作权,如下图(a),但为了维护管道,比如想要一个父进程到子进程的数据通道时,在父进程中关闭读出端,子进程中关闭管道的写入端,图(b)。
(a) (b)
通过管道进行的父/子进程通信(半双工通信)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
//读管道
void read_from_pipe(int fd)
{
charmessage[100];
read(fd,message,100);
printf("readfrom pipe:%s",message);
}
//写管道
void write_to_pipe(int fd)
{
char*message = "hello,pipe!\n";
write(fd,message,strlen(message)+1);
}
int main(void)
{
intfd[2];
pid_tpid;
intstat_val;
//先创建管道,再创建子进程
if(pipe(fd))
{
printf("create pipe failed!\n");
exit(1);
}
pid =fork();
switch(pid)
{
case -1:
printf("forkerror!\n");
exit(1);
case 0 :
//子进程关闭写端
close(fd[1]);
read_from_pipe(fd[0]);
exit(0);
default:
//关闭父进程的读端
close(fd[0]);
write_to_pipe(fd[1]);
wait(&stat_val); //??
exit(0);
}
return0;
}
//建立两个管道来实现全双工通信
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
void child_rw_pipe(int rfd,int wfd)
{
char*message1 = "This pipe two,I am child process and I can write butcannot read!!\n";
charmessage2[100];
write(wfd,message1,strlen(message1)+1);
read(rfd,message2,100);
printf("child process read from pipe one:%s:",message2);
}
void parent_rw_pipe(int rfd,int wfd)
{
char*message1 = "This pipe one,I am parent process and I can write butcannot read!!\n";
charmessage2[100];
write(wfd,message1,strlen(message1)+1);
read(rfd,message2,100);
printf("parent process read from pipe two:%s",message2);
}
int main(void)
{
intfd1[2],fd2[2];
pid_tpid;
intstat_val;
printf("There are two pipes\n");
//管道1实现父进程写,子进程读
if(pipe(fd1))
{
printf("create pipe1 failed\n");
exit(1);
}
//管道2实现子进程写,父进程读
if(pipe(fd2))
{
printf("create pipe2 failed\n");
exit(1);
}
pid =fork();
switch(pid)
{
case-1:
printf("create process failed!!\n");
exit(1);
case0:
//子进程
close(fd1[1]); //关闭管道1的写端
close(fd2[0]); //关闭管道2的读端
child_rw_pipe(fd1[0],fd2[1]);
exit(0);
default:
//父进程
close(fd1[0]); //关闭管道1的读端
close(fd2[1]); //关闭管道2的写端
parent_rw_pipe(fd2[0],fd1[1]);
wait(&stat_val);
exit(0);
}
}
通过管道模拟shell命令:
cat file|sort
通过一个管道,将”cat file”的结果通过管道送给命令”sort”。需要用dup()或者dup2()系统调用将标准输入和标准输出联系起来,这里的”catfile”和”sort”命令不是自己来完成,而是通过调用exec函数族来实现的。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
int main(void)
{
intfd[2];
pid_tpid;
intstat_val;
if(pipe(fd))
{
perror("create pipe failed!\n");
exit(0);
}
pid =fork();
switch(pid)
{
case-1:
perror("create process failed!\n");
exit(1);
case0:
dup2(0,fd[0]); //关闭标准输入,从管道读取内容
close(fd[1]); //子进程关闭管道的写端
printf("I amchild program!\n");
if(execlp("sort","sort",NULL))
perror("execlp error!\n");
exit(0);
default:
dup2(1,fd[1]); //关闭标准输出,将要写到标准输出的内容写入管道
close(fd[0]); //父进程关闭管道的读端
printf("Thisis parent process!\n");
if(execlp("cat","cat","a.txt",NULL))
perror("execlp error!\n");
wait(&stat_val);