进程之间的通信:有名管道和无名管道

四、进程之间的通信。
1、 为什么要学习进程之间的通信?
例如:
./1  -> 开启了一个名字为1的进程。
./2  -> 开启了一个名字为2的进程。
通过学习进程之间的通信,使得不同的进程之间都是可以实现数据的交换。例如进程1发送数据给进程2,进程2收到数据之后,根据数据来做不同的事情。(间接地实现进程1控制进程2)

2、在linux下,进程之间的通信方式有哪些,都有什么特点?
1)管道通信。
管道通信分为有名管道与无名管道,管道是一种特殊的文件,进程通过将数据写入到管道中,另外一个进程从管道中读取数据出来。

2)信号。
在linux下,有非常多信号,例如:暂停,继续,停止..,某一个进程通过发送信号给另外一个进程,从而控制另外一个进程。

3)消息队列。
某一个进程把消息发送到队列上,另外一个进程就可以读取队列上的数据,消息队列好处:进程可以读取队列上某一个特定的数据。

4)共享内存。(信号量)
多个进程访问同一片内存区域。

五、学习进程之间的通信。 --- 无名管道
1、 什么是无名管道?作用机制如何?
无名管道只能作用于亲缘关系之间的进程,例如父子进程。
无名管道其实就是一个数组来的,这个数组有两个端,分别是读端与写端,进程想写入数据到管道中,就往写端中写,如果进程想读取管道中的数据,就读取读端上的数据。

2、使用无名管道步骤:
1)申请数组。
   int fd[2];  -> 里面并不是读端与写端。

2)使用函数初始化数组。  -> pipe()   -> man 2 pipe
初始化数组  -> 初始化数组中读端与写端的值。
功能: pipe, - create pipe
        //创建一条管道

头文件:#include <unistd.h>
原型:
    int pipe(int pipefd[2]);

参数:
    pipefd: 一个具有2个int类型数据的数组。

返回值:
    成功:0
    失败:-1

3)初始化成功
pipefd[0]  -> 读端
pipefd[1]  -> 写端

   例子1: 写一个代码测试无名管道中读端与写端的值是多少。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc,char *argv[])
{
    //1、 申请数组
    int fd[2] = {0};
    printf("fd[0] = %d\n",fd[0]);
    printf("fd[1] = %d\n",fd[1]);
    
    //2、 使用pipe()去初始化这个数组
    int ret;
    ret = pipe(fd);
    printf("ret = %d\n",ret);
    if(ret == 0)
    {
        //3、 初始化成功后,第一个成员就是读端
        //                    第二个成员就是写端
        printf("init pipe success!\n");
    }
    
    //4、 打印读端与写端的值。
    printf("fd[0] = %d\n",fd[0]);
    printf("fd[1] = %d\n",fd[1]);
    
    return 0;
}

结果:
fd[0] = 0
fd[1] = 0
ret = 0
init pipe success!
fd[0] = 3    -> 读端
fd[1] = 4    -> 写端

   例子2: 尝试使用无名管道,让父子进程之间进行通信。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc,char *argv[])
{
    //1、 申请数组并初始化数组
    int fd[2] = {0};
    pipe(fd);
    
    //2、 带着这条无名管道去创建一个新的进程。
    pid_t x;
    x = fork();
    
    //3、 通过fork()函数的返回值去判断。
    if(x > 0)
    {
        //4、 父进程:
        //1) 准备缓冲区
        char buf[20] = {0};
        
        //2) 把需要写入的数据放在缓冲区中。
        fgets(buf,sizeof(buf),stdin);
        
        //3) 将缓冲区中的数据写入到无名管道中的写端即可。
        write(fd[1],buf,strlen(buf));
        
        //4) 主动回收子进程的资源。
        wait(NULL);
        
        //5) 父进程正常退出
        exit(0);
    }
    
    if(x == 0)
    {
        //5、 子进程
            //1) 准备缓冲区
        char buf[20] = {0};
        
        //2) 直接读取无名管道中的读端,将数据读取到缓冲区中。
        read(fd[0],buf,sizeof(buf));
        
        //3) 打印一下读取出来的数据。
        printf("from pipe:%s",buf);
        
        //4) 子进程正常退出
        exit(0);
    }
          
    return 0;
          
}

结果:
gec@ubuntu:/mnt/hgfs/GZ2057/09 系统编程/02/code$ ./pipe_test2
nihao
from pipe:nihao

六、学习进程之间通信。 -- 有名管道
1、什么是有名管道?机制如何?
无名管道是一个数组来的,只能作用于同一个文件中。  -> 只能作用于亲缘关系之间的进程。
有名管道是一个文件来的,文件存在于文件系统中,所以所有的进程都可以看到这个文件。

机制:有名管道的机制.jpg

2、如何创建有名管道?  -> mkfifo()  -> man 3 mkfifo
功能: make a FIFO special file (a named pipe)
    //创建一个特殊的管道文件(命名管道)

头文件:#include <sys/types.h>
       #include <sys/stat.h>

原型:
      int mkfifo(const char *pathname, mode_t mode);

参数:
    pathname: 需要创建的管道文件的路径  绝对路径/相对路径   "/home/gec/fifo_test"
    mode:八进制权限   调用mkfifo之前,要先调用umask(0000)设置掩码
          例如: 0777

返回值:
    成功:0
    失败:-1

   例子1: 尝试在家目录创建一个有名管道,名字为fifo_test。

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
       
int main(int argc,char *argv[])
{
    //1、 设置掩码为0000
    umask(0000);
    
    //2、 直接创建有名管道,名字为fifo_test。
    int ret;
    ret = mkfifo("/home/gec/fifo_test",0777);
    
    //3、 如果成功,那么就去家目录下看看有没有fifo_test这个文件。
    if(ret == 0)
    {
        printf("mkfifo success!\n");
    }
    
    return 0;
}

结果:
创建成功,并且在家目录下看到fifo_test这个文件。
gec@ubuntu:~$ ls -l fifo_test 
prwxrwxrwx 1 gec gec 0 Sep 21 02:21 fifo_test

   例子2: 尝试使用有名管道,让两个陌生的进程进行通信。

发送端:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

int main(int argc,char *argv[])
{
    //1. 设置掩码。
    umask(0000);
    
    //2. 创建有名管道。
    int ret;
    ret = mkfifo("/home/gec/fifo_test",0777);
    
    //3. 打开有名管道文件。
    int fd;
    fd = open("/home/gec/fifo_test",O_RDWR);
    
    //4. 准备缓冲区
    char buf[100] = {0};
    
    while(1)
    {
        //5. 从键盘中获取数据,存放在缓冲区中。
        fgets(buf,sizeof(buf),stdin);
        
        //6. 将缓冲区的数据写入到文件。
        write(fd,buf,strlen(buf));
        
        //7. 如果发送了一个"quit"到管道文件中,那么发送端程序就结束。
        //   如果不是,则继续发送。
        if(strncmp(buf,"quit",4) == 0)  
        {
            break;
        }
    }
    
    //8. 关闭文件。
    close(fd);
    
    return 0;
}

作业1:完成有名管道接收端。
      参考: 有名管道的机制.jpg 
      发送端代码  -> fifo/

作业2:使用无名管道,实现子进程发送一个"showbmp"这个字符串给父进程,父进程就显示一张图片。
作业3:完成练习.doc第一题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值