1. 概述:
该demo主要实现linux下进程之间的管道通信(无名, 命名), 相关接口介绍可以参考<<UNIX环境高级编程>>
2. 场景(半双工):
父进程简单地通过管道(无名, 命名)将数据发送给子进程
3. 测试:
/*
demo_process_IPC_pipe.c
进程编程demo(无名管道)
IPC相关的命令: ipcs ipcrm(释放IPC)
查看进程属性: ulimit -a
1. FILE * popen ( const char * command , const char * type )
type 为 "r" 返回command的标准输出; type 为 "w" 返回command的标准输入
函数执行时, 会调用pipe, fork, exec, dup, wait等相关函数
2. int pclose ( FILE * stream )
3. int dup2(int oldfd, int newfd)
目标描述符将变成源描述符的复制品(STDOUT_FILENO STDIN_FILENO)
换句话说, 两个文件描述符现在都指向同一个文件, 并且是函数第一个参数指向的文件
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#define MAX_BUF 64
int main(int argc, char **argv){
pid_t pid;
int fd[2];
/*
w ->fd[1] → fd[0] → r
即, fd[0]为读打开, f[1]为写打开
*/
if(pipe(fd) < 0){
/*printf("pipe:%s\n", strerror(errno));*/
perror("pipe:");
return -1;
}
/*
父 -> 子
*/
pid = fork();
if(pid < 0){
perror("fork:");
close(fd[0]);
close(fd[1]);
return -1;
}else if(pid == 0){
prctl(PR_SET_NAME, "child_process");
usleep(100 * 1000);
printf("child process\n"); /*子进程*/
char buf[MAX_BUF];
close(fd[1]); /*关闭写*/
/*
读一个写端已被关闭的管道时, 在所有数据都被读取后, 返回0, 表示文件结束
*/
memset(buf, 0, sizeof(buf));
if(read(fd[0], buf,sizeof(buf)) < 0){
perror("read:");
}
printf("child process\t read\t buf = %s\n", buf);
close(fd[0]); /*关闭读*/
}else{
/*
进程重命名
*/
prctl(PR_SET_NAME, "parant_process");
printf("parant process\n"); /*父进程*/
char buf[MAX_BUF] = "demo_process_IPC_pipe";
close(fd[0]); /*关闭读*/
/*
写一个读端已被关闭的管道时, 产生SIGPIPE信号
写入管道的数据长度小于PIPE_BUF字节时是原子操作
超过PIPE_BUF字节的写入可能是非原子的, 内核可能会将数据与其他进程写入的数据交错
*/
if(write(fd[1], buf, strlen(buf)) < 0){
perror("write:");
}
printf("parant process\t write\t buf = %s\n", buf);
wait(NULL);
close(fd[1]); /*关闭写*/
}
return 0;
}
/*
demo_process_IPC_mkfifo.c
进程编程demo(命名管道)
IPC相关的命令: ipcs ipcrm(释放IPC)
查看进程属性: ulimit -a
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#define MAX_BUF 64
#define FIFONAME "/dev/fifo"
int main(int argc, char **argv){
pid_t pid;
if (access(FIFONAME, F_OK) < 0){
if(mkfifo(FIFONAME, 600) < 0){
/*printf("mkfifo:%s\n", strerror(errno));*/
perror("mkfifo:");
return -1;
}
}
/*
父 -> 子
*/
pid = fork();
if(pid < 0){
perror("fork:");
unlink(FIFONAME);
return -1;
}else if(pid == 0){
prctl(PR_SET_NAME, "child_process");
usleep(100 * 1000);
printf("child process\n"); /*子进程*/
int fd = -1;
char buf[MAX_BUF];
/*
O_RDWR : 可读可写方式打开
O_RDONLY : 只读方式打开
O_WRONLY : 只写方式打开
O_NONBLOCK : 非阻塞I/O
置位 : 只读open立即返回
只写open时, 如果没有进程为读打开FIFO, 则返回–1. 并置errno值为ENXIO
不置位 : 只读open要阻塞到有进程为写打开FIFO
只写open要阻塞到有进程为读打开FIFO
*/
fd = open(FIFONAME, O_RDONLY);
if(fd < 0){
perror("open:");
return -1;
}
memset(buf, 0x0, sizeof(buf));
if(read(fd, buf, sizeof(buf)) < 0){
perror("read:");
}
printf("child process\t read\t buf = %s\n", buf);
close(fd);
}else{
/*
进程重命名
*/
prctl(PR_SET_NAME, "parant_process");
printf("parant process\n"); /*父进程*/
int fd = -1;
char buf[MAX_BUF] = "demo_process_IPC_mkfifo";
fd = open(FIFONAME, O_WRONLY);
if(fd < 0){
perror("open:");
return -1;
}
/*
写入管道的数据长度小于PIPE_BUF字节时是原子操作
超过PIPE_BUF字节的写入可能是非原子的, 内核可能会将数据与其他进程写入的数据交错
*/
if(write(fd, buf, strlen(buf)) < 0){
perror("write:");
}
printf("parant process\t write\t buf = %s\n", buf);
wait(NULL);
close(fd);
//remove(FIFONAME);
unlink(FIFONAME);
}
return 0;
}
#Makefile
CC := gcc
INCLUDE = -I /home/demo/include/
all:
$(CC) demo_process_IPC_pipe.c $(INCLUDE) -o demo_process_IPC_pipe -Wall -Werror
$(CC) demo_process_IPC_mkfifo.c $(INCLUDE) -o demo_process_IPC_mkfifo -Wall -Werror
clean:
rm demo_process_IPC_pipe demo_process_IPC_mkfifo