进程DAY3

1.为什么要进行进程间的通信呢?通信的目

1. 实现进程间的数据传递
2. 实现进程间的数据共享
3. 实现进程间的事件的通知等等

2Linux中进程间通信的发展

3Linux中进程间通信的方式

早期的进程间通信方式:
有名管道、无名管道、信号 ---------- 同一台主机上进程间的通信
System V IPC 对象
共享内存、消息队列、信号量 ------ 同一台主机上进程间的通信
BSD socket ------ 不同主机上进程间的通信 ( 网络编程中要研究 )

3-1、无名管道

3-1-1、特点

1 》只能用于具有亲缘关系的进程间的通信 : 父子进程、兄弟进程
2 》半双工的通信模式,具有固定的读端和写端, 一端进行读操作,一端进行写操作
3 》管道可以看成是一种特殊的文件,对于它的读写可以使用文件 IO read write close 函数。
注意: 无名管道不属于任何文件系统,存在于内核中
4 》无名管道在应用层角度来说,是有 2 个文件描述符来标识他, fd [ 0 ] 表示读端 fd [ 1 ] 表示写端
管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符 fd [ 0 ] fd [ 1 ] 。其
fd [ 0 ] 固定用于读管道,而 fd [ 1 ] 固定用于写管道

3-1-2、创建无名管道

#include <unistd.h>
int pipe ( int fd [ 2 ])
/*
参数 1 :保存 2 个文件描述符的数组
返回值:成功 0 , 失败 -1
*/
close ( fd ); // 关闭

3-1-3、使用--亲缘关系进程间的通信

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
//创建管道
int fd[2]= {0};
int res = pipe(fd);
if(res<0)
{
perror("pipe error");
return -1;
}
//创建子进程
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid ==0) //子进程 fd[0] fd[1]
{
//关闭读端
close(fd[0]);
char buf_write[256] = {0};
//给管道中写数据
fgets(buf_write, sizeof(buf_write), stdin);
write(fd[1], buf_write, sizeof(buf_write));
close(fd[1]);
}
else if(pid>0) //父进程 fd[0] fd[1]
{
//关闭写端
close(fd[1]);
char buf_read[256] = {0};
//从管道中读取数据
read(fd[0], buf_read, sizeof(buf_read));
printf("read data = %s\n", buf_read);
//关闭读端
close(fd[0]);
}
return 0;
}

3-1-4、测试一下无名管道的容量: 64KB

#include <stdio.h>
#include <unistd.h>
int main()
{
int fd[2] = {0};
int res = pipe(fd);
if(res<0)
{
perror("pipe error");
return -1;
}
//给管道中写数据
char buf[1024]={0};
int count = 1;
while(1)
{
write(fd[1], buf, 1024);
printf("写入了%dKB数据\n", count);
count++;
}
close(fd[0]);
close(fd[1]);
return 0;
}

3-1-5、无名管道使用时需要注意的点

当管道中无数据时,读操作会阻塞
向管道中写入数据时, linux 将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入
数据。如果读进程不读走管道缓冲区中的数据,那么写操作将会一直阻塞。
只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的
SIGPIPE 信号 ( 通常 Broken pipe 错误 )
在系统中是不允许程序向没有读端的管道中写入数据! 不然会造成管道破裂!
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main()
{
//创建管道
int fd[2]= {0};
int res = pipe(fd);
if(res<0)
{
perror("pipe error");
return -1;
}
//关闭读端
close(fd[0]);
//创建子进程
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid ==0) //子进程 fd[0] fd[1]
3-2、有名管道
3-2-1、为什么会引入有名管道呢
{
//关闭读端
close(fd[0]);
char buf_write[256] = {0};
//给管道中写数据
fgets(buf_write, sizeof(buf_write), stdin);
write(fd[1], buf_write, sizeof(buf_write));
close(fd[1]);
exit(0);
}
else if(pid>0) //父进程 fd[0] fd[1]
{
int status=0;
wait(&status);
if(WIFEXITED(status))
{
printf("子进程正常退出\n");
}
else if(WIFSIGNALED(status))
{
printf("子进程是通信信号退出,信号的值为%d\n", WTERMSIG(status));
}
//关闭写端
close(fd[1]);
char buf_read[256] = {0};
//从管道中读取数据
read(fd[0], buf_read, sizeof(buf_read));
printf("read data = %s\n", buf_read);
//关闭读端
close(fd[0]);
}
return 0;
}

3-2、有名管道

对无名管道的优化,无名管道只实现有亲缘关系的通信,没有亲缘则需要有名通道

3-2-2、特点

1 》无名管道只能用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围
2 》有名管道可以使互不相关的两个进程互相通信。有名管道可以通过路径名来指出,并且在文件系统中可见
3 》进程通过文件 IO 来操作有名管道, open\read\write\close
4 》有名管道遵循先进先出规则, 从头开始读,写入的追加在尾巴处!
5 》不支持如 lseek () 操作
6 》有名管道本质上就是一个文件

3-2-3、创建有名管道

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *filename,mode_t mode);
/*
参数1: 有名管道的名称
参数2:权限 8进制的数表示 0777 0664
返回值: 成功0 失败 -1
*/
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
int main()
{
int res = mkfifo("./fifo_1", 0777);
if(res <0)
{
perror("mkfifo error");
return -1;
}
printf("mkfifo ok\n");
return 0;
}

3-2-4、使用有名管道实现一下非亲缘关系的进程间的通信

//写数据
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
int main()
{
//创建有名管道
int res = mkfifo("./fifo_2", 0664);
if(res<0 && errno!=EEXIST)//保证管道存在的情况下不会报错!
{
perror("mkfifo error");
return -1;
}
//打开有名管道文件
int fd = open("./fifo_2", O_WRONLY);
if(fd<0)
{
perror("open error");
return -1;
}
//写入数据
char buf_write[256] = {0};
while(1)
{
memset(buf_write, 0, sizeof(buf_write));
fgets(buf_write, sizeof(buf_write), stdin);
write(fd, buf_write, sizeof(buf_write));
}
close(fd);
return 0;
}
//文件2
//读数据
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
int main()
{
//创建有名管道
int res = mkfifo("./fifo_2", 0664);
if(res<0 && errno!=EEXIST)
{
perror("mkfifo error");
return -1;
}
//打开有名管道文件
int fd = open("./fifo_2", O_RDONLY);
if(fd<0)
{
perror("open error");
return -1;
}
//读数据
char buf_read[256] = {0};
while(1)
{
memset(buf_read, 0, sizeof(buf_read));
read(fd, buf_read, sizeof(buf_read));
printf("read data =%s\n", buf_read);
}
close(fd);
return 0;
}

  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值