【Linux】管道

本文详细介绍了Linux中的管道通信,包括匿名管道和命名管道。管道是半双工、单向通信,常用于具有亲缘关系的进程间。匿名管道通过fork共享,命名管道则不受进程关系限制。管道的读写有特定规则,并涉及阻塞和非阻塞模式。FIFO文件是命名管道的一种形式,其打开规则与普通文件不同。

管道是Linux中进程间通信的一种方式,从一个进程连接到另一个进程的一个数据流称为一个管道。
管道具有半双工,单向通信的特点。

匿名管道

#include <unistd.h>
功能:创建一匿名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,用于接收函数返回的两个文件描述符。其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回-1

管道特点

只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
管道是面向字节流传输数据的。
进程退出,管道释放,所以管道的生命周期随进程。
内核会对管道操作进行同步(访问临界资源的一定时序性)与互斥(访问临界资源同一时间的唯一性)。
管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。

 使用fork来共享管道。

使用fork来共享管道的原理就是创建一个子进程,子进程复制了父进程的描述符表,因此也有两个描述符,并且他们指向的是同一个管道。这时候因为他们两个都能访问这个管道,因此他们就可以进行通信了。但是因为管道是半双工单向通信,因此在通信之前需要确定数据流向。

管道读写规则

当没有数据可读时:
1. O_NONBLOCK disable塞阻:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
2. O_NONBLOCK enable非阻塞:read调用返回-1,errno值为EAGAIN。
当管道被写满时:
1.  O_NONBLOCK disable塞阻:write调用阻塞,直到有进程读走数据。
2. O_NONBLOCK enable非阻塞:调用返回-1,errno值为EAGAIN。
如果写入端全部被关闭,这时候如果读取数据,读取完管道中的数据,然后read返回0。
如果读取端全部被关闭,这时候如果写入数据,write操作会产生SIGPIPE信号,导致write进程退出。
当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

PIPE_BUF即为管道的缓存大小。 POSIX.1规定当写入管道的长度小于PIPE_BUF字节时必须是原子的:即写入数据作为连续序列写入管道。 超过PIPE_BUF字节的写入可能是非原子的:内核可能会将数据与其他进程写入的数据交错。 POSIX.1要求PIPE_BUF至少为512字节,在Linux上,PIPE_BUF为4096字节。

命名管道

命名管道可以应用于同一主机上的任意进程间通信(而不仅限于亲缘关系进程)。
FIFO文件就是命名管道,是一种特殊类型的文件。

创建命名管道

1. 通过命令创建:makefifo

mkfifo filename

2. 通过代码创建

int mkfifo(const char *filename,mode_t mode);
filename:管道文件路径名
mode:管道文件权限
成功返回0,失败返回-1.

 

int main(int argc, char *argv[])
{
 mkfifo("FIFO", 0644);
 return 0;
}

命名管道打开规则

命名管道是一个特殊类型的文件,使用时需要用户自己打开,所以具有打开特性。通过open打开。

当打开命名管道是为读操作时
1. O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO。
2. O_NONBLOCK enable:立刻返回成功。
当打开命名管道是为写操作时
1. O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO。
2. O_NONBLOCK enable:立刻返回失败,错误码为ENXIO。
以读写方式打开不会阻塞。

### Linux 管道使用教程 #### 一、基本概念 管道Linux 中一种重要的进程间通信机制,能够将一个命令的标准输出作为下一个命令的标准输入。这种特性使得多个简单工具组合起来完成复杂任务成为可能[^1]。 #### 二、无名管道 无名管道主要用于有亲缘关系的进程间的通讯,即父子进程或者兄弟进程之间。其特点是单向传输数据,并且只能由一对进程访问。创建无名管道通常通过 `pipe()` 函数实现,在调用此函数前建立好管道,则 fork 后子进程中也会拥有该管道副本并可对其进行操作[^4]。 ```c #include <unistd.h> int pipe(int pipefd[2]); // 返回值:成功返回0;失败返回-1 ``` 当执行上述代码后会得到两个文件描述符组成的数组`pipefd[]`,其中第一个元素代表读取端而第二个则是写入端。对于父/子进程来说可以根据需求关闭不需要的那一端来确保不会发生死锁现象。 #### 三、有名管道(FIFO) 相比起无名管道,FIFO 不仅可以在不相关联的进程间传递消息,而且支持全双工模式(尽管大多数情况下还是采用半双工的方式工作)[^3]。要创建 FIFO 文件需借助 mkfifo 命令或是在程序内部利用相应 API 完成: ```bash mkfifo my_fifo_file ``` 之后就可以像对待普通文件一样打开它来进行读写了: ```c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int fd = open("my_fifo_file", O_WRONLY); write(fd,"hello world\n",strlen("hello world\n")); close(fd); /* 或者 */ int fd = open("my_fifo_file",O_RDONLY); char buf[80]; read(fd,buf,sizeof(buf)); printf("%s",buf); close(fd); ``` #### 四、应用实例 - 统计当前系统中的进程数量 这里给出一个简单的例子展示如何运用 shell 内置功能配合管道达成特定目的——计算正在运行着多少个进程: ```shell ps aux | wc -l ``` 这条指令先列出所有活动进程(`ps aux`)再将其交给单词计数工具处理(`wc -l`),最终得出总数目。 #### 五、注意事项 虽然管道提供了便捷高效的 IPC 方案之一,但在某些场景下或许 TCP/IP 协议栈更为合适,尤其是在跨主机甚至互联网级别的分布式环境中[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值