管道通信顾名思义就是创建一根管道,这个管道有读写两端
管道有两种:匿名管道和命名管道
1.匿名管道
匿名管道只能父子进程间通信,如图,他会创建两个读写端分别对应父子进程,只要父子进程分别关闭读,或者写端,就可以一个进程发送信息给另一个进程。
规则:
1.如果没有数据可读,或者管道满的时候,read和write调用都会阻塞
2.如果有读写端被关闭,调用返回0
3.写入的数据量小于PIPE_BUF时,linux将保证写.入的原子性
写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性
代码实现,详细注释:
#include<stdio.h>
#include<unistd.h>
#include<memory.h>
#include<stdlib.h>
int main()
{
char buf[100] = "This is message!\n";
int fds[2];
if (pipe(fds) == -1) //创建匿名管道
perror("pipe"), exit(1);
pid_t pid = fork();//创建子进程
if (pid == 0)
{
//关闭子进程管道读描述符
close(fds[0]);
//子进程写消息进管道
if (write(fds[1], buf, strlen(buf)+1) == -1)
{
perror("write");
exit(1);
}
printf("i'm son,write in buf is:%s", buf);
close(fds[1]);
}
else
{
memset(buf, 0, sizeof(buf));
//关闭父进程管道写描述符
close(fds[1]);
//父进程从管道读内容,如果此时子进程还没被创建出来,
//read会堵塞,所以一定会读到数据
if (read(fds[0], buf, sizeof(buf)) == -1)
perror("read"), exit(1);
printf("i'm father,read from buf is:%s", buf);
close(fds[0]);
}
return 0;
}
代码执行如图
2.命名管道
理解了匿名管道,命名的就好理解了,命名的管道就是有一个进程会创建出来这个管道,然后其他进程也可以通过这个管道的名字一起来通信
这个命名管道经过测试,就是一个跟文件一样的东西,如果编译的话,会在当前目录下生成,,所以其他进程打开这个管道需要加上路径,不然会打不开
代码实现:
创建端.cpp
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
int main()
{
mkfifo("mypipe", 0664);
int outfd = open("mypipe", O_WRONLY);
if (outfd == -1)
perror("open "), exit(1);
char buf[100] = {
};
int n = sizeof(buf);
while (fgets(buf, n, stdin))
{
write(outfd, buf, strlen(buf));
memset(buf, 0, n);
}
close(outfd);
return 0;
}
加入端.cpp
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
int main()
{
//注意这里打开的路径是之前创建的
int infd = open("mypipe", O_RDONLY);
if (infd == -1)
perror("open mypipe"), exit(1);
char buf[10] = {
};
int n = 0;
while ((n = read(infd, buf, sizeof(buf))) > 0)
{
if (strlen(buf) > 0)
{
printf("recv from pipe :%s\n", buf);
}
memset(buf, 0, sizeof(buf));
}
close(infd);
unlink("mypipe"); //删除管道
return 0;
}
所以管道通信局限性还是很大,不够好