Linux进程间通信的管道方式(C语言)

        大家好,我是练习编程时长两年半的个人练习生昆工第一ikun,昨天分享了线程间通信,今天我们来分享一下进程间通信的一种方法——管道。管道又分为无名管道和有名管道,二者的区别在于是否能在文件系统中可见,下面我将来介绍这两种方式。


目录

一、无名管道

1.特点

2.创建无名管道

①所用函数:pipe();

②实例

3.无名管道的读写特性

①读特性

②写特性

③实例 

二、有名管道

1.特点

2.有名管道的创建 

①所用函数:mkfifo();

②实例


一、无名管道

1.特点

①创建之后在文件系统中不可见

②以半双工的方式进行通信

③拥有固定的读端和写端

④只能用于具有亲缘关系的进程间通信

2.创建无名管道

①所用函数:pipe();

#include <unistd.h>

int pipe(int pipefd[2]);

参数:
    pipefd:存放无名管道读端和写端的数组首地址
    pipefd[0] -- 读端
    pipefd[1] -- 写端
    
返回值:
    成功返回0,失败返回-1;

②实例

利用无名管道实现子进程从键盘上输入数据,父进程将数据打印到终端,代码如下:

/*===============================================
 *   文件名称:pipe.c
 *   创 建 者:     
 *   创建日期:2022年08月10日
 *   描    述:利用无名管道实现子进程从键盘上输入数据,父进程将数据打印到终端
 ================================================*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int fd[2];
    int ret = pipe(fd);      //创建无名管道
    if(ret < 0)
    {
        perror("pipe");
        exit(-1);
    }
    pid_t pid = fork();     //创建子进程
    if(pid == 0)
    {
        char buf[64];
        fgets(buf, 64, stdin);        //从键盘输入数据
        buf[strlen(buf)-1] = '\0';     
        write(fd[1], buf, 64);        //将获取到的数据写入无名管道中

    }
    else
    {
        char buf1[64];
        memset(buf1, 0, 64);         //清空缓冲区
        read(fd[0], buf1, 64);       //读取无名管道中的数据
        printf("%s\n", buf1);        

    }

    return 0;
} 

3.无名管道的读写特性

①读特性

a.写端存在:

管道有数据:返回读到的字节数

管道无数据:阻塞

b.写端不存在:

管道有数据:返回读到的字节数

管道无数据:返回0

②写特性

a.读端存在:

管道有空间:返回写入的字节数

管道无空间:阻塞,直到有空间为止

b.读端不存在:

无论管道是否有空间,管道破裂

③实例 

计算管道大小和使管道破裂并打印管道破裂的信号

/*===============================================
 *   文件名称:pipe_size_broken.c
 *   创 建 者:     
 *   创建日期:2022年08月10日
 *   描    述:计算管道大小和使管道破裂并打印管道破裂的信号
 ================================================*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int status;
    int fd[2];
    int ret = pipe(fd);    //创建无名管道
    if(ret < 0)
    {
        perror("pipe");  
        exit(-1);
    }

    //close(fd[0]);          //使管道破裂则关闭管道的读取端,计算管道空间大小则不关闭
    pid_t pid = fork();    //创建子进程
    if(pid == 0)
    {
        int n = 0;
        char buf[2];
        while(1)
        {
            strcpy(buf, "a");         //在写入端循环写入数据,将管道空间装满
            write(fd[1], buf, 1);
            n++;                      //计数
            printf("%d\n", n);
        }
        exit(0);
    }
    else
    {
        char buf1[64];
        memset(buf1, 0, 64);
        read(fd[0], buf1, 64);
        printf("%s\n", buf1);

    }
    wait(&status);
    printf("%d\n", WTERMSIG(status));    //打印破裂信号
    exit(0);

    return 0;
} 

运行程序,我们可以看到由于管道无空间,所以被阻塞,总空间大小为65536

 将管道的读取端关闭后,我们可以看到管道破裂,并打印除了破裂信号——13)SIGPIPE

二、有名管道

1.特点

①有名管道创建之后会在文件系统中以管道文件的形式存在

②有名管道可以用于任意两个进程间通信

2.有名管道的创建 

①所用函数:mkfifo();

 #include <sys/types.h>
 #include <sys/stat.h>

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

参数:
           pathname:创建管道文件的文件名
           mode:创建管道文件的权限
   
 返回值:
           成功返回0,失败返回-1

②实例

创建一个有名管道,一个进程向管道中输入数据,另一个进程输出数据

/*===============================================
*   文件名称:mkfifo.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:创建有名管道
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>


int main(int argc, char *argv[])
{
    int ret = mkfifo("fifo", 0664);
    if(ret < 0)
    {
        perror("mkfifo");
        exit(-1);
    }
    return 0;
} 

然后,我们编写两个程序分别用于输入和输出

/*===============================================
*   文件名称:mkfifo.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:输入端
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    int fd = open("fifo", O_RDWR);
    char buf[64];
    while(1)
    {
    fgets(buf, 64, stdin);
    buf[strlen(buf)-1] = '\0';
    write(fd, buf, 64);
    }
    close(fd);


    return 0;
} 
/*===============================================
 *   文件名称:cxk.c
 *   创 建 者:     
 *   创建日期:2022年08月10日
 *   描    述:输出端
 ================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    char buf[64];
    int fd = open("fifo", O_RDWR);
    while(1)
    {
        memset(buf, 0, 64);
        read(fd, buf, 64);
        printf("%s\n", buf);
    }
    close(fd);
    return 0;
} 

然后,我们分别在两个终端运行两个程序,可以发现两个进程间可以实现通信

  • 13
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值