####LINUX进程间通信(二、消息队列)
####匿名管道:
头文件:#include
函数原型:int pipe(int fd[2]);
返回值:成功返回0,失败返回错误代码
注:fd:文件描述符数组,fd[0]代表读端,fd[1]代表写端
####用法:
#####单个进程中的管道几乎没有任何用处,通常,调用pipe的进程接着调用fork,从而创建了一个父进程与子进程之间的半双工的IPC通道。在当前进程假如进行读操作时,就可关闭写端(fd[1])如图:
#####示例:假设现有一对父子进程,子进程需要读取屏幕上输入的信息,再通过管道将信息传给父进程,父进程再将该信息打印到屏幕上。
#####分析:
#####①先要清楚哪些资源是父子进程必须共有的,在fork之前就得定义,在此例子中就是匿名管道pipe;
#####②如果当前进程是父进程时:由于要做的是从管道读取数据,那么就关闭写端;读取完成后将数据打印到屏幕上;
#####③如果当前进程是子进程:关闭读端;将stdin的信息读取并写入到管道中,等待父进程读取。
#####实现如下:
#include
#include
#include
#include
#include
#include
int main()
{
//creat pipe
int fd[2] = {0};
if(pipe(fd) == -1){
perror("pipe");
exit(1);
}
//pipe create success
int res = fork();
if(res > 0){
//father
close(fd[1]);
char buf[1024] = {0};
ssize_t tmp = read(fd[0],buf,sizeof(buf)-1);
if(tmp == -1){
perror("read");
exit(1);
}else if(tmp == 0){
printf("read done\n");
exit(0);
}else{
printf("father read : %s",buf);
}
}else if(res == 0){
//child
close(fd[0]);
char tmp[256] = {0};
printf("child say : ");
fflush(stdout);
read(0,tmp,sizeof(tmp)-1);
if(write(fd[1],tmp,strlen(tmp)) == -1){
perror("write");
exit(1);
}
//子进程正常退出
close(fd[1]);
exit(0);
}else{
perror("fork");
exit(1);
}
return 0;
}
####管道特点:
#####1、只能用于有亲缘关系的进程之间的通信;
#####2、管道生命周期随进程;进程退出管道释放;
#####3、管道拥有同步与互斥机制;
#####4、具有半双工的特点;(要想实现双向通信,可建立两个管道)
####管道读写规则
#####1、当管道中没有数据可读时:若pipe采取的是不阻塞方法,则直接read返回-1;采取是阻塞时,进程阻塞直到等待数据可以读;
####2、当管道满时:采用不阻塞方式将调用返回-1;反之write阻塞,直到有程序读走数据。
#####注:若想修改是否阻塞选项,需使用pipe2函数。具体用法自行man一下。
int pipe2(int pipefd[2], int flags);
####命名管道(FIFO):相当于创建一个文件,通过一个进程读 一个写来完成通信
#####使用方法:FIFO创建成功后,一般的文件I/O函数(close,read,write,unlink等)都可用于FIFO。
//使用mkfifo命令创建一个名为filaname的命名管道。
mkfifo filename
//使用函数创建
函数原型:int mkfifo(const char* filename, mode_t mode);
参数:filename为所要创建的文件名,mode为文件权限.
返回值:成功返回0,失败返回-1
#####注:FIFO是一种文件类型(p)
####匿名管道与命名管道的区别:
#####1、匿名管道必须适用于有亲缘关系的进程之间;命名管道没有要求;
#####2、匿名管道通过fd[0],fd[1]进行读写;命名管道通过特殊的FIFO文件进行读写。
#####示例:client——server进程使用FIFO进行通信。
#####首先由服务器端先执行,创建FIFO文件,然后read阻塞等待有人向文件中写入数据,一旦client执行并写入数据,便开始进行“通信”。(由于是半双工,便只模拟实现了从client向server端发送数据)
server.c
#include
#include
#include
#include
#include
#include
int main()
{
if( mkfifo("myfifo",0666) == -1){
perror("mkfifo");
exit(1);
}
//FIFO creat success
char buf[1024] = {0};
int rfd = open("myfifo",O_RDONLY);
while(1){
printf("please wait...\n");
if(rfd > 0){
//open myfifo success
printf("client say : ");
fflush(stdout);
ssize_t count = read(rfd,buf,sizeof(buf)-1);
if(count > 0){
buf[count] = 0;
printf("%s",buf);
}else if(count == 0){
printf("client close\n");
exit(0);
}else{
perror("read");
exit(1);
}
}else{
//open return -1,open failed
perror("open");
exit(1);
}
}
close(rfd);
return 0;
}
client.c
#include
#include
#include
#include
#include
#include
#include
int main()
{
int wfd = open("myfifo",O_WRONLY);
if(wfd == -1){
perror("open");
exit(1);
}
//open success
char buf[1024] = {0};
while(1){
printf("client send : ");
fflush(stdout);
ssize_t count = read(0,buf,sizeof(buf)-1);
if(count > 0){
buf[count] = 0;
write(wfd,buf,strlen(buf));
}else{
perror("read");
exit(1);
}
}
close(wfd);
return 0;
}
Makefile
.PHONY:all
all : server client
server:server.c
gcc $^ -o $@
client:client.c
gcc $^ -o $@
.PYHONY : clean
clean:
rm server client myfifo
####运行结果显示:
#####注:1、一定要先运行server,否则没有创建myfifo文件,client将会打开失败,直接报错终止。
#####2、当同时运行多个client,一个server时,server将会全部接受client写入的信息;
#####3、当运行多个server,多个client时,此时一个client写入数据,随机只有一个server进程读取到信息。(同步互斥的体现)