FIFO读写产生SIGPIPE信号

本文通过一个实例介绍了在FIFO(命名管道)操作中如何触发SIGPIPE信号。当尝试向已关闭的管道写入数据时,进程会收到SIGPIPE信号,导致'Broken pipe'错误。这种情况通常发生在CentOS 6.3环境下使用GCC编译的程序中。后续内容会深入探讨相关细节。

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

以前一直在听说产生SIGPIPE信号,我但我平时遇得少,没怎么管它,今天一小心就遇到

先看代码吧

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#define FIFO_FN   "/tmp/test"

void catch_pipe(int n) {
	printf("signo:%d\n", n);
}

int main() {
	signal(SIGPIPE, catch_pipe);
	if ((mkfifo(FIFO_FN, S_IRWXU | S_IRGRP | S_IROTH) < 0)
			&& (errno != EEXIST)) {
		perror("mkfifo:");
	}
	int fo = fork();
	if (fo > 0) {
		int fd = open(FIFO_FN, O_WRONLY);
		if (fd == -1) {
			perror("open pipe");
		}
		int flg = fcntl(fd, F_GETFL);
		if (flg < 0) {
			perror("fcntl:");
		}
		flg |= O_NONBLOCK;
		fcntl(fd, F_SETFL, flg);
		int wr;
		char buf[1024];
		printf("writing...\n");
		sleep(1);
		if ((wr = write(fd, buf, 1)) < 0) {
  
  //如果不 捕获或是忽略的话,程序遇到SIGPIPE 信号就直接退出,没有下面的了
			perror("write:");
<think>我们正在讨论FIFO(命名管道)在C语言中的使用。根据引用[1],命名管道使用read和write函数进行数据读写。下面我将详细解释FIFO管道的创建、读写操作,并提供代码示例。###1.FIFO管道基本概念FIFO(命名管道)是一种特殊的文件类型,它允许无亲缘关系的进程间通信(IPC)。与匿名管道(pipe)不同,FIFO在文件系统中有一个路径名,可以通过文件I/O函数操作。关键特性:-**命名管道**:在文件系统中有一个路径名,通过`mkfifo`函数创建。-**阻塞特性**:-打开FIFO进行读操作(open(O_RDONLY))会阻塞,直到另一个进程以写方式打开(O_WRONLY)。-打开FIFO进行写操作(open(O_WRONLY))会阻塞,直到另一个进程以读方式打开(O_RDONLY)。-**数据传递**:通过`read`和`write`系统调用进行数据读写。###2.FIFO管道使用步骤####步骤1:创建FIFO使用`mkfifo`函数创建命名管道:```c#include<sys/types.h>#include<sys/stat.h>intmkfifo(constchar*pathname,mode_tmode);```-`pathname`:管道文件路径-`mode`:文件权限(如0666)-成功返回0,失败返回-1####步骤2:打开FIFO使用`open`函数打开管道:```c#include<fcntl.h>intfd=open("fifo_path",O_RDONLY);//读端intfd=open("fifo_path",O_WRONLY);//写端```注意:打开方式必须匹配(一个读端和一个写端),否则会阻塞。####步骤3:读写数据使用`read`和`write`进行数据传输:```cssize_tread(intfd,void*buf,size_tcount);ssize_twrite(intfd,constvoid*buf,size_tcount);```-`fd`:open返回的文件描述符-`buf`:数据缓冲区-`count`:读写字节数####步骤4:关闭和删除```cclose(fd);//关闭管道unlink("fifo_path");//删除管道文件(可选)```###3.完整代码示例####示例1:写进程(writer.c)```c#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<sys/stat.h>#include<unistd.h>#defineFIFO_PATH"/tmp/myfifo"//定义FIFO文件路径intmain(){//创建FIFO管道(如果已存在则忽略错误)if(mkfifo(FIFO_PATH,0666)==-1){perror("mkfifo");//如果已存在,可以继续}//以写方式打开FIFO(会阻塞直到读端打开)intfd=open(FIFO_PATH,O_WRONLY);if(fd==-1){perror("open");exit(EXIT_FAILURE);}//写入数据charmessage[]="HellofromFIFO!";if(write(fd,message,sizeof(message))==-1){perror("write");close(fd);exit(EXIT_FAILURE);}printf("Writer:Sentmessage\n");close(fd);//关闭管道return0;}```####示例2:读进程(reader.c)```c#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<unistd.h>#defineFIFO_PATH"/tmp/myfifo"intmain(){//以读方式打开FIFO(会阻塞直到写端打开)intfd=open(FIFO_PATH,O_RDONLY);if(fd==-1){perror("open");exit(EXIT_FAILURE);}//读取数据charbuffer[256];ssize_tnum_bytes=read(fd,buffer,sizeof(buffer));if(num_bytes==-1){perror("read");close(fd);exit(EXIT_FAILURE);}//添加字符串结束符并打印buffer[num_bytes]='\0';printf("Reader:Received:%s\n",buffer);close(fd);//可选:删除FIFO文件unlink(FIFO_PATH);return0;}```###4.运行说明1.编译两个程序:```bashgccwriter.c-owritergccreader.c-oreader```2.先运行读进程(会阻塞等待写进程):```bash./reader```3.再运行写进程(读进程收到消息后两者都会退出):```bash./writer```###5.关键注意事项-**阻塞行为**:`open`调用会阻塞直到另一端也被打开。如果需要非阻塞模式,可以使用`O_NONBLOCK`标志,但要注意数据完整性和同步问题。-**数据边界**:FIFO保证数据按写入顺序传递(FIFO特性),但不保证消息边界(连续写入可能被合并读取)。-**多进程安全**:多个进程同时读写同一个FIFO时,需要额外同步机制(如信号量)。-**管道容量**:FIFO有内部缓冲区大小限制(通常几KB),写满后会阻塞写操作,直到有空间。###6.应用场景-命令行工具间通信(如`grep`和`sort`通过管道连接)-服务进程与客户端进程通信(如日志服务)-解耦生产者和消费者进程---###相关问题1.**如何实现FIFO管道的非阻塞模式?**2.**FIFO管道与匿名管道(pipe)有何区别?**3.**多个进程同时写入FIFO时如何保证数据完整性?**4.**FIFO管道在Linux系统中的最大容量是多少?**5.**如何用FIFO实现双向进程通信?**</think>### C语言中FIFO管道的使用详解 FIFO(命名管道)是Linux/Unix系统中实现**进程间通信(IPC)** 的重要机制,它允许无亲缘关系的进程通过文件系统路径进行通信。以下是详细用法和代码示例: --- #### 1. FIFO管道核心操作 ```c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> // 创建FIFO int mkfifo(const char *pathname, mode_t mode); // 读写操作(使用文件I/O函数) ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); ``` - **`mkfifo`**:创建命名管道文件(返回0成功,-1失败) - **`pathname`**:管道文件路径(如`"/tmp/myfifo"`) - **`mode`**:文件权限(如`0666`) --- #### 2. 完整使用流程 ##### 步骤1:创建FIFO管道 ```c #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> int main() { // 创建FIFO文件 if (mkfifo("/tmp/myfifo", 0666) == -1) { perror("mkfifo failed"); exit(EXIT_FAILURE); } printf("FIFO created at /tmp/myfifo\n"); return 0; } ``` **注意**:需先运行此程序创建管道文件(实际使用时通常由服务端创建)[^1]。 --- ##### 步骤2:写入进程(writer.c) ```c #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> int main() { int fd; char msg[] = "Hello FIFO!"; // 以写方式打开FIFO(阻塞直到读端打开) fd = open("/tmp/myfifo", O_WRONLY); // 写入数据 ssize_t bytes_written = write(fd, msg, strlen(msg)+1); printf("Writer: Sent %zd bytes\n", bytes_written); close(fd); return 0; } ``` ##### 步骤3:读取进程(reader.c) ```c #include <fcntl.h> #include <stdio.h> #include <unistd.h> int main() { int fd; char buffer[256]; // 以读方式打开FIFO(阻塞直到写端打开) fd = open("/tmp/myfifo", O_RDONLY); // 读取数据 ssize_t bytes_read = read(fd, buffer, sizeof(buffer)); printf("Reader: Received %zd bytes: %s\n", bytes_read, buffer); close(fd); // 可选:删除管道文件 unlink("/tmp/myfifo"); return 0; } ``` --- #### 3. 编译与运行 ```bash # 编译 gcc create_fifo.c -o create_fifo gcc writer.c -o writer gcc reader.c -o reader # 执行 ./create_fifo # 创建管道文件(只需运行一次) ./reader & # 启动读进程(后台运行) ./writer # 启动写进程 ``` **输出示例**: ``` Reader: Received 12 bytes: Hello FIFO! Writer: Sent 12 bytes ``` --- #### 4. 关键特性详解 1. **阻塞行为**: - 读进程`open()`会阻塞,直到写进程打开管道 - 写进程`open()`会阻塞,直到读进程打开管道 - 可通过`O_NONBLOCK`标志设为非阻塞模式 2. **数据传输**: - 数据按写入顺序传输(严格FIFO) - 管道有缓冲区大小限制(通常64KB) - 写满时`write()`会阻塞,读空时`read()`会阻塞 3. **进程关系**: ```mermaid graph LR A[进程A] -->|写入| F[/tmp/myfifo] F -->|读取| B[进程B] C[进程C] -->|写入| F F -->|读取| D[进程D] ``` 支持多对多通信模型,任意进程可通过路径访问[^1]。 --- #### 5. 应用场景 1. **服务端-客户端通信** 服务端持续监听FIFO,处理客户端请求 2. **日志收集系统** 多个进程写入日志,单个日志处理器读取 3. **命令行工具协作** 如:`producer | filter | consumer` 4. **解耦耗时操作** GUI进程通过FIFO委托后台进程处理任务 --- #### 6. 注意事项 1. **原子性**:小于`PIPE_BUF`(通常512B)的写入是原子的 2. **错误处理**: - 读端关闭后继续写入会触发`SIGPIPE`信号 - 使用`fcntl()`设置文件描述符属性 3. **清理**:程序退出前应`unlink()`管道文件 --- ### 相关问题 1. **如何实现FIFO的非阻塞模式?** 2. **FIFO管道与匿名管道(pipe)有何区别?** 3. **多个进程同时写入FIFO时如何避免数据混乱?** 4. **FIFO在Linux系统中的最大容量是多少?** 5. **如何用FIFO实现双向进程通信?**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值