管道是linux进程间通信的一种方式,如命令ps -ef | grep ntp
无名管道的特点:
1、只能在亲缘关系进程间通信(父子或兄弟)
2、半双工(固定的读端和固定的写端)
3、是特殊的文件,可以用read、write等,只能在内存中
管道函数原型:
#include <unistd.h>
int pipe(int fds[2]);
函数pipe
用于创建一个无名管道,如果成功,fds[0]存放可读的文件描述符,fds[1]存放可写文件描述符,并且函数返回0,否则返回-1。
通过调用pipe获取这对打开的文件描述符后,一个进程就可以从fds[0]中读数据,而另一个进程就可以往fds[1]中写数据。当然两进程间必须有继承关系,才能继承这对打开的文件描述符。
管道不像真正的物理文件,不是持久的,即两进程终止后,管道也自动消失了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fds[2] = {0};
pipe(fds);
char szBuf[32] = {'\0'};
if(fork() == 0) //表示子进程
{
close(fds[1]); //子进程关闭写
sleep(2); //确保父进程有时间关闭读,并且往管道中写内容
if(read(fds[0], szBuf, sizeof(szBuf)) > 0)
puts(szBuf); //打印输出szBuf
close(fds[0]); //子关闭读
exit(0);
}else{ //表示父进程
close(fds[0]); //父关闭读
write(fds[1], "hello", 6);
waitpid(-1, NULL, 0); //等子进程关闭读
close(fds[1]); //父关闭写
exit(0);
}
return 0;
}
运行结果:
hello
管道两端的关闭是有先后顺序的,如果先关闭写端则从另一端读数据时,read函数将返回0,表示管道已经关闭;
但是如果先关闭读端,则从另一端写数据时,将会使写数据的进程接收到SIGPIPE
(发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开)信号,如果写进程不对该信号进行处理,将导致写进程终止,如果写进程处理了该信号,则写数据的write函数返回一个负值,表示管道已经关闭。
无名管道只能在亲缘关系的进程间通信大大限制了管道的使用,有名管道突破了这个限制,通过指定路径名的范式实现不相关进程间的通信
创建FIFO文件的函数原型:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
返回值:创建成功,则返回0,否则-1。
pathname
为要创建的FIFO文件的全路径名
mode
为文件访问权限
创建管道文件代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("args error\n");
return -1;
}
if(mkfifo(argv[1], 0666) == -1)
{
perror("make fifo failed");
return -2;
}
return 0;
}
yu@ubuntu:~/0126/fifo$ gcc -o fifo fifo.c
yu@ubuntu:~/0126/fifo$ ./fifo newfile
yu@ubuntu:~/0126/fifo$ ls
fifo fifo.c newfile
yu@ubuntu:~/0126/fifo$ ls -l
total 12
-rwxrwxr-x 1 yu yu 7404 Jan 26 04:18 fifo
-rw-rw-r-- 1 yu yu 233 Jan 26 04:18 fifo.c
prw-rw-r-- 1 yu yu 0 Jan 26 04:18 newfile
删除FIFO文件的函数原#include
#include <unistd.h>
int main()
{
unlink("newfile");
return 0;
}
yu@ubuntu:~/0126/fifo$ gcc -o delfifo delfifo.c
yu@ubuntu:~/0126/fifo$ ls
delfifo delfifo.c fifo fifo.c newfile
yu@ubuntu:~/0126/fifo$ ./delfifo
yu@ubuntu:~/0126/fifo$ ls
delfifo delfifo.c fifo fifo.c
注意:用命令mkfifo创建,不能重复创建,用命令unlink删除
非亲缘两进程间通过FIFO通信实战
1、执行mkfifo myfifo
创建命名管道FIFO文件myfifo
2、write.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fdFifo = open("myfifo", O_WRONLY);
write(fdFifo, "hello", 6);
close(fdFifo);
return 0;
}
gcc -o write write.c
生成write
3、read.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define BUFSIZE 128
int main()
{
char szBuf[BUFSIZE];
int fdFifo = open("myfifo", O_RDONLY);
if(read(fdFifo, szBuf, sizeof(szBuf)) > 0)
{
puts(szBuf);
}
close(fdFifo);
return 0;
}
gcc -o read read.c
生成read
4、此时执行./read
,进入阻塞状态
5、另开一个终端,执行./write
read
执行成功,屏幕输出hello