Linux——进程间通信——管道(文件)通信

目录

前言

一、有名管道

1、用法

2、管道分类

3、有名管道的创建

4、思考:如何进程a要将键盘获取的数据传递给另一个进程b?

 5、有名管道实现进程间通信

二、无名管道

1、无名管道的创建

2、管道操作分为以下步骤

3、无名管道实现进程间通信

前言

进程间通信方法:

(1)管道

(2)信号量

(3)共享内存

(4)消息队列

(5)套接字

一、有名管道

1、用法

  • | 命令
  • 举例:ps -ef|grep "sleep"

两个进程通信:比如a,b进程,a想管道中写入数据,b读取数据;

2、管道分类

(1)有名管道

(2)无名管道

区别:有名管道可以在任意进程间通信;无名管道主要在父子进程间通信(重点)

3、有名管道的创建

①命令:mkfifo  (属于系统调用)

②打开管道:open()

③读数据:read()

④写数据:write()

⑤关闭管道:close()

4、思考:如何进程a要将键盘获取的数据传递给另一个进程b?

(不能用文件传递),效率太慢。

创建管道之后,它会在内存上分配一块空间,表面上卡把数据写入管道中了,实际上是吧数据写入内存中了。另外一个程序是从内存中读取数据的,所以效率是比较高的。

管道文件的大小永远为0。如下图所示:

 5、有名管道实现进程间通信

(1)参考代码:

//a.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>

int main()
{
    int fd=open("fifi",O_WRONLY);
    assert(fd!=-1);

    printf("fd=%d\n",fd);
    write(fd,"hello",5);
    close(fd);

}


//加入循环后:
//c.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>

int main()
{
    int fd=open("fifi",O_WRONLY);
    assert(fd!=-1);
  
   // printf("fd=%d\n",fd);
    while(1)
    {
        printf("input:\n");
        char buff[128]={0};
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3)==0)
        {
             break;
        }   
    
    write(fd,buff,strlen(buff));
    }
    close(fd);

}
//b.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>

int main()
{
    int fd=open("./fifi",O_RDONLY);
    assert(fd!=-1);

    printf("fd=%d\n",fd);
    char buff[128]={0};
    read(fd,buff,127);
    printf("read:%s\n",buff);
    close(fd);

}

//加入循环后:
//d.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>

int main()
{
    int fd=open("./fifi",O_RDONLY);
    assert(fd!=-1);
    
    printf("fd=%d\n",fd);
    while(1)
    {
        char buff[128]={0};
        if(read(fd,buff,127)==0)
        {
            break;
        }
    printf("read:%s\n",buff);
    }
    close(fd);

}

 (2)管道的特点

①管道必须读、写进程同时open,否则会阻塞;

  • 阻塞的情况:(只有写进程open或只有读进程open)

 

 正确的通信:读写进程同时open(打开两个窗口)

②如果管道中没有数据,那么read就会阻塞。

③管道的写端关闭,读read返回值为0;

④管道打开的时候只读和只写方式,读写方式是未定义的。

⑤管道是半双工的(某一时刻只能选择一个方向)(重点)

    通信方式:单工、半双工、全双工。

⑥无论有名还是无名, 写入管道的数据都在内存中。(重点)

 ⑧管道的读端关闭,写会产生异常(发送信号SIGPIPE)(可以改变信号的响应方式验证一下)。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
#include<signal.h>

//发送信号
void fun(int sig)
{
    printf("sig=%d\n",sig);   
}

int main()
{
    signal(SIGPIPE,fun);
    int fd=open("fifi",O_WRONLY);
    assert(fd!=-1);
  
   // printf("fd=%d\n",fd);
    while(1)
    {
        printf("input:\n");
        char buff[128]={0};
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3)==0)
        {
             break;
        }   
    
    write(fd,buff,strlen(buff));
    }
    close(fd);

}

二、无名管道

使用pipe创建无名管道,**只能进行父子间的通信;

pipe是一个系统调用

1、无名管道的创建

int pipe(int fds[2]);
//pipe()成功返回0,失败返回-1;
//fds[0]是管道读端的描述符
//fds[1]是管道写端的描述符

2、管道操作分为以下步骤

(1)父进程调用pipe函数开辟管道,得到两个文件描述符指向管道的两端;

(2)父进程用fork创建子进程,那么子进程也有两个文件描述符指向同一管道;

(3)父进程关闭管道文件读端,子进程关闭写端。父进程可以往管道里写数据,子进程可以从管道中读数据,这样就在父子进程之间建立管道,实现进程间通信。

3、无名管道实现进程间通信

参考代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>

int main()
{
    int fd[2];
    assert(pipe(fd)!=-1);

    pid_t pid=fork();//先open,再fork,父子进程共享打开的文件描述符
    assert(pid!=-1);

    if(pid==0)
    {
        close(fd[1]);
        char buff[128]={0};
        read(fd[0],buff,127);
        printf("child read:%s\n",buff);
        close(fd[0]);
    }
    else
    {
        close(fd[0]);
        write(fd[1],"hello",5);
        close(fd[1]);
    }
    exit(0);
}

如有错误,敬请指正。

您的收藏与点赞都是对我最大的鼓励和支持!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sweep-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值