目录
一【无名管道】
1、无名管道的简述
2、管道的特点:
3、无名管道的创建
案例:父进程写,子进程读,使用无名管道
4、无名管道读写的特点
案例:使用无名管道实现ps -A |grep bash
二【有名管道(命名管道)FIFO】
1、有名管道的概述
2、FIFO文件的创建
案例:实现两个进程通信:
一【无名管道】
1、无名管道的简述
1)无名管道又简称为管道。是一种特殊类型的文件,在应用层体现为两个打开的文件描述符。
2、管道的特点:
管道是最古老的的UNIX IPC.方式.
1、半双工,数据在同一时刻只能在一个方向上流动。
2、数据只能从管道的一端写入,从另一端读出。
3、写入管道中的数据遵循先入先出的规则。
4、管道所传送的数据是无格式的,这要求管道的读出方与写入方必须事先约定好数据的格式,如多少字节算一个消息等。
5、管道不是普通的文件,不属于某个文件系统,其只存在于内存中。
6、管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。
7、从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据。
8、管道没有名字,只能在具有公共祖先的进程之间使用。
3、无名管道的创建
头文件:include<unistd.h>
函数原型:int pipe( int filedes[2] )
功能:
经过由参数filedes返回的两个文件描述符
参数:
filedes为int类型的数组的首地址,其存放了管道的文件描述符fd[0],fd[1]
filedes[0]为读而打开,filedes[1] 为写而打开管道,filedes[0]的输出是filedes[1]的输入。
返回值:成功返回1,失败返回-1
案例:父进程写,子进程读,使用无名管道
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include <stdio.h> #include<unistd.h> #include<sys/wait.h> #include <string.h> int main(int argc, char const *argv[]) { int fd[2]; pipe(fd); pid_t pid = fork(); if(pid==0) { close(fd[1]); printf("子进程正在等待读取父进程n"); char buf[128]; memset(buf,0,128); read(fd[0],buf,sizeof(buf)); printf("子进程读到消息为:%sn",buf); close(fd[0]); _exit(-1); } if(pid>0) { close(fd[0]); printf("请输入你要发送的信息:n"); char buf[128]; scanf("%s",&buf); write(fd[1],buf,sizeof(buf)); close(fd[1]); wait(NULL); } return 0; }
运行:
4、无名管道读写的特点
1)默认使用read函数从管道中读数据是堵塞的。
2)调用write函数从管道中写数据,当缓存区满的时候,也会阻塞。
3)通信过程中,读端口全部关闭后,写进程向管道写数据的时候,写进程会收到SIGPIPE信号退出。
案例:使用无名管道实现ps -A |grep bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56#include <stdio.h> #include<unistd.h> #include<sys/wait.h> int main(int argc, char const *argv[]) { int fd[2]; pipe(fd); int i =0; for( i;i<2;i++) { pid_t pid = fork(); if(pid==0) break; } //子进程1 ps -A 写 //让标准输出1 作为管道写口。 if(i == 0) { close(fd[0]); dup2(fd[1],1); execlp("ps","ps","-A",NULL); _exit(-1); } //子进程2 grep bash 读的标准输入0,所以让标准输入0作为管道读口 if(i==1) { close(fd[1]); dup2(fd[0],0); execlp("grep","grep","bash",NULL); _exit(-1); } //父进程 if(i==2) { close(fd[0]); close(fd[1]); while(1) { pid_t pid = waitpid(-1,NULL,WNOHANG); if(pid<0) { break; } if(pid==0) { continue; } if(pid>0) { printf("子进程%d已经被回收n",pid); } } } return 0; }
二【有名管道(命名管道)FIFO】
主要用于不相关的进程间通信。抽象为物理内存的一个文件。
1、有名管道的概述
特点:
1、半双工,数据在同一时刻只能在一个方向上流动。
2、写入FIFO中的数据遵循先入先出的规则。
3、FIFO所传送的数据是无格式的,这要求FIFO的读出方与写入方必须事先约定好数据的格式,如多少字节算一个消息等。
4、FIFO在文件系统中作为一个特殊的文件而存在,但FIFO中的内容却存放在内存中。
5.管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。
6、从FIFO读数据是一次性操作,数据一旦被读,它就从FIFO中被抛弃,释放空间以便写更多的数据。
7、当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后使用。
8、FIFO有名字,不相关的进程可以通过打开命名管道进行通信
2、FIFO文件的创建
头文件:
#include <sys/types.h>
#include <sys/stat.h>
函数原型:int mkfifo( ..const char *pathname,mode .t mode) ;
参数:
pathname:.E.IFO.的路径多土文件多。
mode: mode_t类型的权限描述符。
返回值
成功:返回0。
失败:如果文件已经存在,则会出错且返回-1。
阻塞方式打开管道:
1、open以只读方式打开FIFO时,要阻塞到某个进程为写而打开此FIFO2、open以只写方式打开FIFO时,要阻塞到某个进程为读而打开此FIFO。
3、open以只读、只写方式打开FIFO时会阻塞,调用read函数从FIFO里读数据时read也会阻塞。
4、通信过程中若写进程先退出了,则调用read函数从FIFO里读数据时不阻塞;若写进程又重新运行,则调用read函数从FIFO里读数据时又恢复阻塞。
5、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到SIGPIPE信号)退出。
6、调用write函数向FIFO里写数据,当缓冲区已满时write也会阻塞。
案例:实现两个进程通信:
写进程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <stdio.h> #include<unistd.h> #include <sys/types.h> #include<fcntl.h> #include <sys/stat.h> #include<string.h> int main(int argc, char const *argv[]) { mkfifo("my_fifo",0666); int fd1 = open("my_fifo",O_WRONLY);//以写的方式打开,会阻塞到对方以读的方式打开 if(fd1 == -1) { perror("open"); return -1; } printf("写端openn"); while(1) { char buf[128]=""; printf("请输入要发送的数据:"); //获取数据 fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]=0; //发送 write(fd1,buf,strlen(buf)); if(strcmp(buf,"bye")==0) { break; } } close(fd1); return 0; }
读进程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include <stdio.h> #include<unistd.h> #include <sys/types.h> #include<fcntl.h> #include <sys/stat.h> #include<string.h> int main(int argc, char const *argv[]) { mkfifo("my_fifo",0666); int fd1 = open("my_fifo",O_RDONLY);//会阻塞到对方以写的方式打开 if(fd1 == -1) { perror("open"); return -1; } printf("写端openn"); while(1) { char buf[128]=""; read(fd1,buf,sizeof(buf)); printf("收到的数据为:%sn",buf); if((strcmp(buf,"bye"))==0) { break; } } close(fd1); return 0; }
拓展:条件编译一份代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58#include <stdio.h> #include<unistd.h> #include <sys/types.h> #include<fcntl.h> #include <sys/stat.h> #include<string.h> int main(int argc, char const *argv[]) { #ifdef WRITE mkfifo("my_fifo",0666); int fd1 = open("my_fifo",O_WRONLY); #endif #ifdef READ mkfifo("my_fifo",0666); int fd1 = open("my_fifo",O_RDONLY); #endif if(fd1 == -1) { perror("open"); return -1; } #ifdef WRITE printf("写端openn"); #endif #ifdef READ printf("读端openn"); #endif #ifdef READ while(1) { char buf[128]=""; read(fd1,buf,sizeof(buf)); printf("收到的数据为:%sn",buf); if((strcmp(buf,"bye"))==0) { break; } } #endif #ifdef WRITE while(1) { char buf[128]=""; printf("请输入要发送的数据:"); //获取数据 fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]=0; //发送 write(fd1,buf,strlen(buf)); if(strcmp(buf,"bye")==0) { break; } } #endif close(fd1); return 0; }
以非阻塞方式打开管道:
1、先以只读方式打开:如果没有进程已经为写而打开一个FIFO,只读open成功,并且open不阻塞。
2、先以只写方式打开:如果没有进程已经为读而打开一个FIFO,只写open将出错返回-1。
3、read、write读写命名管道中读数据时不阻塞。
4、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到SIGPIPE信号)退出。
注意: open函数以可读可写方式打开FIFO文件时的特点:
1、open不阻塞。
2、调用read函数从FIFO里读数据时read会阻塞。
3、调用write函数向FIFO里写数据,当缓冲区已满时write也会阻塞
最后
以上就是聪慧小海豚最近收集整理的关于linux系统编程之管道通信一【无名管道】二【有名管道(命名管道)FIFO】的全部内容,更多相关linux系统编程之管道通信一【无名管道】二【有名管道(命名管道)FIFO】内容请搜索靠谱客的其他文章。
发表评论 取消回复