无名管道和有名管道

本文详细介绍了无名管道和有名管道在Linux系统中的使用。无名管道适用于有亲缘关系的进程间通信,具有不可见、半双工、固定读写端的特点。有名管道则可通过文件系统进行通信,适用于任意进程。文中通过实例展示了管道的创建、读写特性和大小限制,以及管道破裂的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、无名管道

无名管道用于有亲缘关系的进程间的通信,管道字如其名,它就像在两个进程之间铺设了一条管道,进程通过管道进行数据交互。无名管道是没有名字的,它由pipe或者pipe2函数创建,与之对应的是有名管道。

1、特点:

​ (1)创建之后再文件系统中不可见

​ (2)以半双工的方式进行通信
半双工(Half Duplex)数据传输指数据可以在一个信号载体的两 个方向上传输,但是不能同时传输。

​ (3)拥有固定的读端(0)和写端(1)

​ (4)只能用于具有亲缘关系的进程间通信

2、无名管道的创建–pipe

#include <unistd.h>//头文件

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

3、无名管道的读写性

​ (1)读–特性:

​ <1>写端存在:

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

​ 管道无数据:阻塞

​ <2>写端不存在:

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

​ 管道无数据:返回0

​ (2)写–特性:

​ <1>读端存在:

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

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

​ <2>读端不存在:

​ 无论管道是否有空间,管道破裂
(3)无名管道的大小
我们可以通过一个while循环让它不断写入,当满了时它就会停止写入,这时也就是它的大小。
实例:

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

int main(int argc, char *argv[])
{ 
    int pfd[2]={0};//定义无名管道数组,只有两个端口,所以大小为2
    int ret=pipe(pfd);//pipe--创建无名管道
    
    char buf[1]={0};//缓冲区大小,每次写入一个
    int size,count=0;
        while(1)
        {
            size=write(pfd[1],buf,1);
            if(size<0)//write写入不成功就退出,并输出错误原因
            {
            	perror("write");
            	exit(-1);
            }
            count=count+size;//循环直到写满
            printf("size=%d\n",count);//输出空间大小
        }
        
    return 0;
} 

在这里插入图片描述
可以看到,当size=65536时,就不动了,说明管道写满了,大小为65536,当然,可能不同系统大小有所差异。
(4)管道的破裂
为便于观察,我们先了解几个判断进程终止和异常的函数

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

pid_t wait(int *wstatus);
参数:
    wstatus:进程结束时,状态信息的首地址
返回值:
    成功返回子进程结束的pid号,失败返回-1;
    如果想得到进程结束的状态信息,可以用以下宏来的到:
    WIFEXITED(wstatus)--判断一个子进程是否正常退出,正常退出为真(1),非正常退出为假(非正数)
    WEXITSTATUS(wstatus)--返回子进程结束的返回值
    WIFSIGNALED(wstatus)--判断是否被信号终止
    WTERMSIG(wstatus)--打印进程信号的编号
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{ 
    int pfd[2]={0};//管道的两个端口
    int ret=pipe(pfd);//创建管道
    if(ret<0)
    {
        perror("pipe");
        exit(-1);
    }
    close(pfd[0]);//关闭读端
    pid_t pid=fork();//创建自进程
    if(pid<0)
    {
        perror("fork");
        exit(-1);
    }
    
    if(pid==0)
    {
        write(pfd[1],"ccvv",4);//向管道写入
        sleep(3);
    }
    else
    {
        int status;//定义状态信息首地址
        wait(&status);
        printf("进程编号:%d\n是否正常退出%d\n信号是否被终止: %d\n",WTERMSIG(status),WIFEXITED(status),WIFSIGNALED(status));
        exit(0);//结束进程
    }
    return 0;
} 

运行结果:
在这里插入图片描述
可以看到WIFEXITED(status)的结果是0,说明为非正常退出,而程序也正常运行,所有就是管道破裂了。

二、有名管道

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

有名管道可以用于任意两个进程间的通信,没有固定的读端和写端。

1、有名管道的创建–mkfifo

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

int mkfifo(const char *pathname, mode_t mode);
参数:
    pathname:创建管道文件的文件名
	mode:管道文件的权限
返回值:
      成功返回0,失败返回-1

2、实例

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

我们首先要创建一个fifo管道:

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

int main(int argc, char *argv[])
{ 
    int ret=mkfifo("fifo",0664);//0664赋文件权限
    //0664--> rw- rw- -w-,每一位依次对应<用户>、<用户组><其他>的权限,每个权限又对应读(r)写(w)执行(x)
    if(ret<0)
    {
        perror("mkfifo");//ret<0,就输出创建错误原因
        exit(-1);
    }

    return 0;
} 

创建之后可以看到,多了一个颜色与其他不同的文件
在这里插入图片描述
然后写入fifo:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{ 
    int fd=open("fifo",O_WRONLY);//以‘仅写’打开管道
    if(fd<0)
    {
        perror("open fifo");
        exit(-1);
    }
    printf("open fifo success\n");
    char buf[64]={0};//定义缓冲区大小
    while(1)
    {
        fgets(buf,64,stdin);//获取输入的字符串
        write(fd,buf,strlen(buf));//写入
    }
    close(fd);
    return 0;
} 

读取fifo:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{ 
    int fd=open("fifo",O_RDONLY);//以‘仅读’打开管道
    if(fd<0)
    {
        perror("open fifo");
        exit(-1);
    }
    printf("open fifo success\n");
    char buf[64]={0};
    while(1)
    { 
        read(fd,buf,64);//读取缓冲区,注:这里的64不能写成strlen(buf),因为两个buf不一样,会读不进去
        fputs(buf,stdout);//输出
    }
    close(fd);
    return 0;
}  

运行结果演示:
只运行write_fifo:
在这里插入图片描述

只运行read_fifo:

在这里插入图片描述
运行write_fifo 并同时运行read_fifo(两个终端):
在这里插入图片描述
可以发现,从write_fifo里输入的值,read_fifo那里也输出了,说明fifo管道将他们连通了,可以传输数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值