您的位置:首页 > 运维架构 > Linux

Linux-进程间通信(一、匿名管道与命名管道)

2017-12-20 15:26 495 查看

LINUX进程间通信(二、消息队列)

匿名管道

头文件:#include<unistd.h>
函数原型:int pipe(int fd[2]);
返回值:成功返回0,失败返回错误代码
注:fd:文件描述符数组,fd[0]代表读端,fd[1]代表写端


用法:

单个进程中的管道几乎没有任何用处,通常,调用pipe的进程接着调用fork,从而创建了一个父进程与子进程之间的[b]半双工的IPC通道。在当前进程假如进行读操作时,就可关闭写端(fd[1])如图:[/b]



[b]示例:假设现有一对父子进程,子进程需要读取屏幕上输入的信息,再通过管道将信息传给父进程,父进程再将该信息打印到屏幕上。[/b]

分析:

①先要清楚哪些资源是父子进程必须共有的,在fork之前就得定义,在此例子中就是匿名管道pipe;

②如果当前进程是父进程时:由于要做的是从管道读取数据,那么就关闭写端;读取完成后将数据打印到屏幕上;

③如果当前进程是子进程:关闭读端;将stdin的信息读取并写入到管道中,等待父进程读取。

实现如下:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

int main()
{
//creat pipe
int fd[2] = {0};
if(pipe(fd) == -1){
perror("pipe");
exit(1);
}

//pipe create
4000
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):相当于创建一个文件,通过一个进程读 一个写来完成通信

[b]使用方法:FIFO创建成功后,一般的文件I/O函数(close,read,write,unlink等)都可用于FIFO。[/b]

//使用mkfifo命令创建一个名为filaname的命名管道。
mkfifo filename

//使用函数创建
函数原型:int mkfifo(const char* filename, mode_t mode);
参数:filename为所要创建的文件名,mode为文件权限.
返回值:成功返回0,失败返回-1


[b]注:FIFO是一种文件类型(p)[/b]

匿名管道与命名管道的区别:

1、匿名管道必须适用于有亲缘关系的进程之间;命名管道没有要求;

2、匿名管道通过fd[0],fd[1]进行读写;命名管道通过特殊的FIFO文件进行读写。

[b]示例:client——server进程使用FIFO进行通信。[/b]

首先由服务器端先执行,创建FIFO文件,然后read阻塞等待有人向文件中写入数据,一旦client执行并写入数据,便开始进行“通信”。(由于是半双工,便只模拟实现了从client向server端发送数据)

server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>

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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

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进程读取到信息。(同步互斥的体现)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: