#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
一,管道进程的pipe函数和dup2函数组合使用父子进程间通信
参数是数组管道文件描述符
pipe参数是:
- fd[0]是读文件描述符,
- fd[2]是写文件描述符
int pipe(int pipefd[2]);
案例1:
/*************************************************************************
> File Name: pipe.c
> Author: songli
> QQ: 2734030745
> Mail: 15850774503@163.com
> CSDN: http://my.csdn.net/Poisx
> github: https://github.com/chensongpoixs
> Created Time: Fri 20 Oct 2017 10:22:29 PM CST
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//管道数组文件描述符
int fd[2];
int ret;
int i, n = 2;
//创建管道
ret = pipe(fd);
//文件描述符
pid_t pid;
if (ret < 0)
{
perror("pipe error");
return -1;
}
for (i = 0; i < n; i++)
{
//创建子进程
pid = fork();
if (pid < 0) // 异常处理
{
perror("fork error");
return -1;
}
else if (pid > 0) // 父进程的操作
{
printf("father fpid:%d, cpid:%d\n", getpid(), pid);
}
else if (pid == 0) //子进程的操作
{
printf("child fpid:%d, cpid:%d\n", getppid(), getpid());
break; //防止子线程创建子进程
}
}
//=============== 子进程的操作=============================
if (i == 0)
{
printf("no child n = %d, cpid:%d\n", i, getpid());
//=================写入数据 =====================
close(fd[0]); //关闭读取文件描述符
//标准输入也是 文件描述符 中的1
dup2(fd[1], STDOUT_FILENO);
// 执行 写入命令
execlp("ps", "ps", "-ef", NULL);
close(fd[1]); //关闭写入文件描述符
return 0; //signal 正常退出
}
if (i == 1)
{
printf("no child n = %d, cpid:%d\n", i, getpid());
//=================写入数据 =====================
close(fd[1]); //关闭 写描述符文件描述符
//标准输出也是 文件描述符 中的1
dup2(fd[0], STDIN_FILENO);
// 执行 写入命令
execlp("grep", "grep", "--color", "bash", NULL);
close(fd[0]); //关闭写入文件描述符
return 0; //signal 正常退出
}
//================= 主进程的操作 ========================
if (i == n)
{
//pcb 进程块pid
pid_t wpid;
int status;
while (1)
{
//等待线程
wpid = waitpid(-1, &status, WNOHANG );
if (wpid == 0) //有子进程程的操作
{
sleep(1);
continue;
}
else if (wpid == -1) // 没有子进程的操作
{
printf("退出子进程的wpid:%d\n", wpid);
exit(0);
}
else if (wpid > 0) //什么原因退出
{
if (WIFEXITED(status)) //正常退出
{
printf("子进程wpid:%d, status:%d\n", wpid, WEXITSTATUS(status));
}
if (WIFSIGNALED(status))
{
printf("子进程wpid:%d, status:%d\n", wpid, WTERMSIG(status));
}
}
}
}
return 0;
}
效果图
1, 和fcntl函数一起使用可以数组read函数非阻塞
/*************************************************************************
> File Name: pipe_fcntl.c
> Author: songli
> QQ: 2734030745
> Mail: 15850774503@163.com
> CSDN: http://my.csdn.net/Poisx
> github: https://github.com/chensongpoixs
> Created Time: Fri 20 Oct 2017 10:47:08 PM CST
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char *argv[])
{
//数组文件描述符
int fd[2];
int ret;
char buf[1024];
//创建管道
ret = pipe(fd);
if (ret < 0)
{
perror("pipe error");
return -1;
}
//pcb进程控制块pid
pid_t pid;
//创建子线程
pid = fork();
if (pid < 0) //异常处理
{
perror("fork error");
return -1;
}
else if (pid > 0) //父进程的处理
{
printf("father fpid:%d, cpid:%d\n", getpid(), pid);
//==============读取数据==================
close(fd[1]); //关闭写文件操作
//================== 在同一个进程中使用非阻塞使用fcntl函数 =========================================
int flags = fcntl(fd[0], F_GETFL );
flags |= O_NONBLOCK;
fcntl(fd[0], F_SETFL, flags);
//=============================================================
while(1)
{
sleep(1);
memset(buf, 0x00, sizeof(buf));
ret = read(fd[0], buf, sizeof(buf));
printf("读取数据的大小:%d buf = %s\n", ret, buf);
}
close(fd[0]);
}
else if (pid == 0) //子进程的操作
{
printf("child fpid:%d, cpid:%d\n", getppid(), getpid());
//========== 写操作===================
close(fd[0]); //关闭读取文件描述符
int i = 0;
while (1)
{
sleep(1);
memset(buf, 0x00, sizeof(buf));
sprintf(buf, "[%d]:[%s]", i++, "陈丽, 杨艳");
write(fd[1], buf, strlen(buf));
}
close(fd[1]);
}
return 0;
}
** 效果图**
二,管道 mkfifio函数的使用
mkfifo命令生成管道文件
mkfifo函数 第一参数路径, 第二是权限
int mkfifo(const char *pathname, mode_t mode);
写入数据
/*************************************************************************
> File Name: fifo_write.c
> Author: songli
> QQ: 2734030745
> Mail: 15850774503@163.com
> CSDN: http://my.csdn.net/Poisx
> github: https://github.com/chensongpoixs
> Created Time: Fri 20 Oct 2017 11:22:50 PM CST
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
// 文件描述符
int fd;
int ret;
//判断是否创建管道文件
if ((ret = access("./myfifo", F_OK)) == -1)
{
//创建管道
ret = mkfifo("./myfifo", 0777);
if (ret < 0)
{
perror("mkfifo error");
return -1;
}
}
//打开文件
fd = open("./myfifo", O_RDWR);
if (fd < 0)
{
perror("open error");
return -1;
}
//=====================写数据到管道中============================
while (1)
{
sleep(1);
write(fd, "陈丽, 杨艳", strlen("杨艳"));
}
close(fd);
return 0;
}
1, 读取数据
/*************************************************************************
> File Name: fifo_read.c
> Author: songli
> QQ: 2734030745
> Mail: 15850774503@163.com
> CSDN: http://my.csdn.net/Poisx
> github: https://github.com/chensongpoixs
> Created Time: Fri 20 Oct 2017 11:31:07 PM CST
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
//文件描述符
int fd;
int ret;
char buf[1024];
//检测是否有管道文件
if ((ret = access("./myfifo", F_OK)) == -1)
{
ret = mkfifo("./myfifo", 0777);
if (ret < 0)
{
perror("mkfifo error");
return -1;
}
}
//打开管道文件
fd = open("./myfifo", O_RDWR);
if (fd < 0)
{
perror("open error");
return -1;
}
//==============读取管道中数据=========================
while (1)
{
//================= 设置read函数非阻塞 ==================
/* int flags = fcntl(fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);*/
sleep(1);
memset(buf, 0x00, sizeof(buf));
ret = read(fd, buf, sizeof(buf));
printf("读取数据:%d, buf = %s\n", ret, buf);
}
//关闭文件
close(fd);
return 0;
}
效果图
三,mmap内存映射的机制
每个应用程序有虚的4个G的内存 由MMU把实际 要用的映射到内存中就是内核
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
//文件描述符
int fd;
int len;
fd = open("./text.log", O_RDWR);
if (fd < 0)
{
perror("open error");
return -1;
}
//文件大小
len = lseek(fd, 0, SEEK_END);
//参数一:NULL
//参数二:文件的大小,不能为0
//参数三:权限
//参数四:是否同步的硬盘中
//参数五:文件指针
//参数六:文件开始位置
void *ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
char *p = (char*)ptr;
strcpy(p, "陈丽");
//参数一:文件指针
//参数二:文件大小
munmap(ptr, len);
//关闭文件
close(fd);
return 0;
}
1, 没有告关系的进程之间通信
写数据的
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//文件描述符
int fd;
int len; //文件大小
int ret; //状态码
//打开文件
fd = open("./text.log", O_RDWR);
if (fd < 0)
{
perror("open error");
return -1;
}
//文件大小
len = lseek(fd, 0, SEEK_END);
//映射到内核中
void * ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
char * p = (char *) ptr;
strcpy(p, "陈丽, 王蓉");
//关闭
munmap(ptr, len);
close(fd);
return 0;
}
读取数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
/**
读取数据mmap_read
**/
int main(int argc, char *argv[])
{
//文件指针
int fd;
int len; //文件大小
void * ptr; //映射内存地址
char buf[1024];
//打开文件
fd = open("./text.log", O_RDWR);
if (fd < 0)
{
perror("open error");
return -1;
}
//文件大小
len = lseek(fd, 0, SEEK_END);
//创建映射
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
//=============读取 map内存的数据===================
//while (1)
//{
//memset(buf, 0x00, sizeof(buf));
// read(fd, buf, sizeof(buf));
char *p = (char *) ptr;
printf("读取数据:%s\n", p);
//}
munmap(ptr, len);
//关闭文件操作
close(fd);
return 0;
}
四, 进程间通信的自定义
/*
*父子进程交替数数。
*/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <error.h>
pid_t pid;
void sig_handler_p(int sig) //parent 父进程
{
static int i = 1;
printf("pid = %d, I'm father\t%d\n", getpid(), i);
sleep(1);
i += 2;
kill(pid, SIGUSR1); //为避免竞态条件出现,应该在捕捉函数内完成数数及信号发送.
}
void sig_handler_c(int sig) //child 子进程
{
static int i = 2;
printf("pid = %d, I am child\t%d\n", getpid(), i);
sleep(1);
i += 2;
kill(getppid(), SIGUSR2);
}
int main(void)
{
struct sigaction newact_p, oldact_p; //父进程使用
struct sigaction newact_c, oldact_c; //子进程使用
//子进程响应SIGUSR1
newact_c.sa_handler = sig_handler_c;
sigemptyset(&newact_c.sa_mask);
newact_c.sa_flags = 0;
sigaction(SIGUSR1, &newact_c, &oldact_c);//注册捕捉信号(捕捉的信号,传入参数新的处理方法,传出参数旧的处理方法)
//父进程响应SIGUSR2
newact_p.sa_handler = sig_handler_p;
sigemptyset(&newact_p.sa_mask);
newact_p.sa_flags = 0;
newact_p.sa_flags |= SA_RESTART;//多加这一行可以将被信号打断的系统调用重启。
sigaction(SIGUSR2, &newact_p, &oldact_p);//注册捕捉信号(捕捉的信号,传入参数新的处理方法,传出参数旧的处理方法)
pid = fork();//此时父子进程都注册了2个信号处理函数,但都只会收到其中一个信号,子进程只收SIGUSR1,父进程只收SIGUSR2
if (pid == 0)
{ //子进程
while (1);
}
else
{ //父进程
raise(SIGUSR2);//自己给自己发信号2
if (wait(NULL))
{ //wait有可能被信号打断。
perror("wait error");
}
//while (1); //或者不使用wait使用这条语句也可以实现。
}
return 0;
}