管道

管道是内核中的数据缓冲区,实现半双工通信。它具备读写特性,当无数据或满时会阻塞,其生命周期随进程。匿名管道通过`pipe()`函数创建,适用于亲缘进程通信;命名管道`mkfifo()`允许非亲缘进程通信,实现更广泛的交互。

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

一、概念

我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”,其本质时内核中的一块缓冲区。

二、特性

1.半双工通信。管道是双向选择,单向通信。

2.读写特性。

如果管道中没有数据,则read会阻塞;如果管道中数据满了,则write会阻塞;

如果管道所有写端关闭,则read读完之返回0而不是阻塞;如果所有读端关闭,则write写完后触发异常退出而不是阻塞。

3.管道自带同步与互斥。

同步:保证数据操作的合理性,时序可控,即我操作完了别人才能操作;

互斥:保证数据操作的时间唯一访问性,即我操作的时候别人不能操作。

(注:管道的操作大小小于PIPE_BUF时,可以保证操作原子性)

4.管道的生命周期随进程,进程生命周期结束则管道生命周期也结束

5.管道提供字节流服务:传输灵活,但是会造成数据粘连没有边界

6.管道仅能用于具有亲缘关系的进程间通信,因为子进程需要通过复制父进程获取管道操作句柄。

三、匿名管道

1,实现函数:int pipe(int pipefd[2])

pipedfd[0]:管道的读取端;    pipefd[1]:管道的写入端

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

2.示例


  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4 #include<stdlib.h>
  5 #include<errno.h>
  6 
  7 int main()
  8 {
  9         int pipefd[2] = {0};
 10         int ret = pipe(pipefd);
 11         if(ret < 0)
 12         {
 13             perror("pipe error");
 14             exit(-1);
 15         }
 16         int pid = fork();
 17         if(pid < 0)
 18         {
 19             perror("fork error");
 20             return -1;
 21         }
 22         else if(pid == 0)
 23         {
 24             char buf[1024] = {0};
 25             close(pipefd[1]);
 26             read(pipefd[0], buf, 1023);
 27             printf("buf = %s\n",buf);
 28         }
 29         else
 30         {
 31             char* ptr = "hello";
 32             close(pipefd[0]);
 33             write(pipefd[1], ptr, strlen(ptr));
 34 
 35         }
 36         return 0;
 37 
 38 }

这样就简单的实现了父子进程之间通过管道实现数据传输。值得注意的是:管道的创建要在fork子进程之前,并且由于管道的读写特性,用户在操作管带的时候最好是没有用到哪一端就关闭掉那一端。

四、命名管道

1.特点

  (1)有名字,管道文件是开头为p的文件,而管道文件就是命名管道的名字

  (2)在磁盘上存在这样的文件

  (3)伪文件,该文件在磁盘大小永远为0

  (4)在内核中有一个对应的缓冲区

  (5)半双工的通信方式

  (6)命名管道可以实现非亲缘关系的进程间通信

2.实现函数:int mkfifo(const char *pathname, mode_t mode)

参数:pathname:管道文件路径及名称

mode:管道文件操作权限

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

3.示例:利用命名管道实现两个进程间通信

首先写一个读取数据的程序

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

int main(int argc, char *argv[])
{
    char *fifo = "./test.fifo";
    umask(0);
    int ret = mkfifo(fifo, 0664);
    if (ret < 0 && errno != EEXIST) {
	perror("mkfifo error");
	return -1;
    }
    int fd = open(fifo, O_RDONLY);
    if (fd < 0) {
	perror("open error");
	return -1;
    }
    while(1) {
	sleep(5);
	char buf[1024] = {0};
	read(fd, buf, 1023);
	printf("buf:[%s]\n", buf);
    }
    close(fd);
    return 0;
}

接下来是写入数据的程序

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

int main(int argc, char *argv[])
{
    char *fifo = "./test.fifo";
    umask(0);
    int ret = mkfifo(fifo, 0664);
    if (ret < 0 && errno != EEXIST) {
	perror("mkfifo error");
	return -1;
    }
    int fd = open(fifo, O_WRONLY);
    if (fd < 0) {
	perror("open error");
	return -1;
    }
    while(1) {
	char buf[1024] = {0};
	scanf("%s", buf);
	write(fd, buf, strlen(buf));
    }
    close(fd);
    return 0;
}

这样两个进程同时运行,在写端输入数据,就可以在读端接收到数据,从而实现非亲缘关系的进程间通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值