#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#define FIFO_NAME "myfifo"
#define BUFFER_SIZE 1024
void error_handling(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
int main() {
int fd, res;
char buffer[BUFFER_SIZE];
mode_t fifo_mode = S_IFIFO | 0666;
// 创建命名管道
if (mkfifo(FIFO_NAME, fifo_mode) == -1 && errno != EEXIST) {
error_handling("mkfifo");
}
// 写端
if (fork() == 0) {
fd = open(FIFO_NAME, O_WRONLY);
if (fd == -1) {
error_handling("open for writing");
}
for (int i = 1; i <= 100; i++) {
snprintf(buffer, sizeof(buffer), "%d", i);
res = write(fd, buffer, strlen(buffer));
if (res == -1) {
error_handling("write");
}
// 发送换行符,以便读端按行读取
res = write(fd, "\n", 1);
if (res == -1) {
error_handling("write newline");
}
}
close(fd);
exit(EXIT_SUCCESS);
}
// 读端
else {
fd = open(FIFO_NAME, O_RDONLY);
if (fd == -1) {
error_handling("open for reading");
}
int sum = 0;
while (1) {
res = read(fd, buffer, sizeof(buffer) - 1);
if (res <= 0) {
if (res == 0) {
break;
} else {
error_handling("read");
}
}
buffer[res] = '\0';
int num;
sscanf(buffer, "%d", &num);
sum += num;
}
close(fd);
printf("Sum of numbers from 1 to 100 is: %d\n", sum);
// 删除命名管道
if (unlink(FIFO_NAME) == -1) {
error_handling("unlink");
}
}
return 0;
}
- 命名管道创建:使用
mkfifo
函数创建命名管道,如果管道已存在,忽略该错误(errno != EEXIST
)。
- 写端操作:
- 使用
fork
创建子进程作为写端。
- 使用
open
以只写模式打开命名管道。
- 使用
snprintf
将数字转换为字符串,通过write
写入管道,并在每个数字后写入换行符,以便读端按行读取。
- 读端操作:
- 父进程作为读端,使用
open
以只读模式打开命名管道。
- 使用
read
按行读取管道中的数据,使用sscanf
将读取的字符串转换为数字并累加到sum
中。
- 错误处理:
- 对于
mkfifo
、open
、write
、read
和unlink
等可能出错的函数,通过自定义的error_handling
函数进行错误处理,打印错误信息并退出程序。
- 同步性:
- 通过按行写入和读取数据,确保了读写操作的同步性,避免数据丢失或混乱。并且父进程等待子进程写完数据后(子进程关闭写端后,读端
read
返回0),读端才会结束读取操作。