进程间通信:
任何一个进程的全局变量在另一个进程中都看不到,
所以进程和进程之间不能相互访问,要交换数据必须通过内核,
在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,
进程2再从内核缓冲区把数据读走,
内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
进程间通信的方式:
在进程间完成数据传递需要借助操作系统提供特殊的方法,
进程间的七大通信方式
signal、file、
pipe(管道(Pipe)及有名管道(named pipe):就是pipe和fifo)、
shm、sem、msg、socket。
如:文件(fifo 就是文件IO)、管道(管道是一种最基本的IPC机制,也称匿名管道,pipe)、
信号(signal)、信号量(semaphore)、共享内存(shm)、
消息队列(msg)、套接字(UNXI域套接字、网络套接字(Network socket))、(FIFO)命名管道等。
现今常用的进程间通信方式有:
管道 (使用最简单)
信号 (开销最小)
共享映射区 (无血缘关系)
本地套接字 (最稳定)
管道:
1 管道的本质是一块内核缓冲区,内部的实现是环形队列
2 管道有读写两端,读写两端是两个文件描述符
3 数据的流向是从管道的写端流到管道的读端(数据的流向是单项的)
4 数据被读走之后,在管道中就消失了
5 pipe只能用于有血缘关系的进程间通信
6 管道的读写两端是阻塞的
7 管道的大小默认4k,但是会根据实际情况做适当调整。
pipe用于父子进程间通信:
1、父进程创建pipe
2、父进程调用fork函数创建子进程
3、父进程关闭一端
4、子进程关闭一端
5、父进程和子进程分别执行read或者write操作
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
//创建管道
//int pipe(int pipefd[2]);
int fd[2];
int ret = pipe(fd);
if(ret<0)
{
perror("pipe error");
return -1;
}
//创建子进程
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid>0)
{
//关闭读端
close(fd[0]);
sleep(5);
write(fd[1], "hello world", strlen("hello world"));
wait(NULL);
}
else
{
//关闭写端
close(fd[1]);
char buf[64];
memset(buf, 0x00, sizeof(buf));
int n = read(fd[0], buf, sizeof(buf));//read函数是阻塞的,因此读到数据之前等父进程写完数据,再继续执行
printf("read over, n==[%d], buf==[%s]\n", n, buf);
}
return 0;
}
利用pipe父子进程执行ps aux|grep bash思路分析
//使用pipe完成ps aux | grep bash操作
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
//创建管道
//int pipe(int pipefd[2]);
int fd[2];
int ret = pipe(fd);
if(ret<0)
{
perror("pipe error");
return -1;
}
//创建子进程
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid>0)
{
//关闭读端
close(fd[0]);
//将标准输出重定向到管道的写端
dup2(fd[1], STDOUT_FILENO);
execlp("ps", "ps", "aux", NULL);
perror("execlp error");
wait(NULL);//回收子进程
}
else
{
//关闭写端
close(fd[1]);
//将标准输入重定向到管道的读端
dup2(fd[0], STDIN_FILENO);
execlp("grep", "grep", "--color=auto", "bash", NULL);
perror("execlp error");
}
return 0;
}
管道的读写行为
读操作
有数据
read正常读,返回读出的字节数
无数据
写端全部关闭
read解除阻塞,返回0, 相当于读文件读到了尾部
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/wait.h>
int main(int argc,char *argv[])
{
int fd[2];
int ret = pipe(fd);
if(ret<0)
{
perror("pipe error");
return -1;
}
write(fd[1],"hello world",strlen("hello world"));
close(fd[1]);//关闭写端
char buf[<