1.进程间通信常用的方式
 
 1 
 ,管道通信:有名管道,无名管道  
 
 
 2 
 ,信号 
 -  
 系统开销小  
 
 
 3 
 ,消息队列 
 - 
 内核的链表  
 
 
 4 
 ,信号量 
 - 
 计数器  
 
 
 5 
 ,共享内存  
 
 
 6 
 ,内存映射  
 
 
 7 
 ,套接字 
 
 
2.管道的概念
 
 
2.1本质
 
  *内核缓冲区  
 
 
  
  *伪文件 
  - 
  不占用磁盘空间  
 
 
  
 2.2特点
 
  *两部分: 读端,写端,对应两个文件描述符 ,分别是数据写端流入,读端流出  
 
 
  
  * 
  操作管理的进程被销毁之后 
  , 
  管道自动被释放  
 
 
  
  *管道默认是阻塞的  
 
 
  
2.3管道的原理
 
  *内部实现方式:队列 ,环形队列  
 
 
  
  *特点:先进先出  
 
 
  
  *缓冲区大小 :默认4K ,大小会根据实际情况做适当调整  
 
 
  
 2.4管道的局限性
 
  *队列: 数据只能读取一次,不能重复读取  
 
 
  
  *单工:遥控器  
 
 
  
  *半双工:对讲机 
 
 
  
  
 2.5管道的读写行为
 
   读操作: 
  
 
   
           有数据 :read(fd[1]) 正常读,返回读出的字节数  
  
 
   
           无数据:如果写端被全部关闭时,read 
   返回 
   0 
   ,相当于读文件到了尾部。 
  
 
   
                          如果写端没有全部关闭时,read阻塞  
  
 
   
   写操作: 
  
 
   
           读端全部关闭: 
  
 
   
                   管道不断的写入数据可能管道会破裂,进程被终止 , 
  
 
   
                   就是内核给当前进程发送信号SIGPIPE- 13,默认处理动作  
  
 
   
           读端没全部关闭: 
  
 
   
                   缓冲区写满了:write 
   阻塞 
  
 
   
                   缓冲区没满   :write 
   继续写,直到写满,阻塞 
  
 
  2.6查看管道缓冲区大小
 
    命令 :ulimit -a  
   
 
    
 
   3.无名管道
3.1无名管道的创建
 
 函数:int pipe(int fd[2])  
 
 
            fd‐传出参数:  
 
 
            fd[0]‐ 
 读端  
 
 
            fd[1]‐ 
 写端  
 
 
 返回值:  
 
 
           0 
 :成功  
 
 
           ‐1 
 :创建失败 
 
 
 
 历程: 
 
 
include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
        int fd[2];
        int rnt;
        rnt = pipe(fd);
        if(rnt == -1)
        {
                printf("创建无名管道失败\n");
                perror("pipe error");
                exit(0);
        }
        else
        {
                printf("读端:%d\n",fd[0]);
                printf("写端:%d\n",fd[1]);
        }
        close(fd[0]);
	    close(fd[1]);
        return 0;
}
运行结果:

3.2父子进程使用无名管道通信
 
  示例:实现  
  ps aux| grep "bash"  
 
 
  
  示例功能:父进程使用 ps aux命令进行查询,子进程使用grep "bash"进行读取 
 
 
  
  数据重定向: 
  dup2  
 
 
  
 #include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
	int fd[2];
	int rnt;
	rnt = pipe(fd);
	if(rnt == -1)
	{
		printf("创建无名管道失败\n");
		perror("pipe error");
		exit(0);
	}
	pid_t pid = fork();
	if(pid == -1)
	{
		printf("fork failed!\n");
		perror("fork");
		exit(0);
	}
	if(pid == 0)//子进程进行读取数据,grep "bash"
	{
		printf("这是一个子进程\n");
		close(fd[1]);
		dup2(fd[0],STDIN_FILENO);//将要在终端读取数据,重定向到管道去读取
		execlp("grep","grep","bash","--color=auto",NULL);
		exit(0);
	}
    if(pid > 0)//父进程将数据写到管道里去 ps aux
	{
		close(fd[0]);//写之前要把管道的读关闭
		printf("这是一个父进程\n");
		dup2(fd[1],STDOUT_FILENO);//将数据重定向到管道去 不然就显示到终端了
		execlp("ps","ps","aux",NULL);
		wait(NULL);//阻塞回收子进程
		exit(0);
	}
	else
	{
		printf("读端:%d\n",fd[0]);
		printf("写端:%d\n",fd[1]);
	}
	close(fd[0]);
	close(fd[1]);
	return 0;
}
 
  运行结果: 
 
 
  
 
  
  PS:进行管道读写的时候,读的时候要把写关闭,写的时候要把读关闭 
 
 
  
  
 3.3使用场景
有血缘关系的进程间通信(如:父子进程之间的通信)
4.有名管道
4.1有名管道的创建
 
 函数形式: 
 int mkfifo(const char \*filename,mode_t mode);  
 
 
 功能:创建管道文件  
 
 
 参数:管道文件文件名,权限,创建的文件权限仍然和 
 umask 
 有关系。  
 
 
 返回值:创建成功返回 
 0 
 ,创建失败返回 
 -1 
 。  
 
 
 e--1 
 
 
 write --2 
 
 
 read --4 
 
 
 
 
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
        int ret;
        ret = mkfifo("/home/czx/mkfifo",0777);
        if(ret == -1)
        {
                printf("有名管道创建失败\n");
                perror("myfifo");
                return -1;
        }
        else
                printf("有名管道创建成功\n");
        return 0;
}
~运行结果:
PS :创建管道的时候,只会创建一个指向内核缓冲区的节点,调用open()的时候才会生成管道.
 
 示例: 
 
 
 功能:一个进程利用管道进行读取数据,一个进程利用管道进行写数据 
 
 
 
 利用管道进行读数据: 
 
 
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
        int ret;
        char readBuff[20] = {0};
        int read_ret;
        int fd;
        ret = mkfifo("/home/czx/mkfifo",0775);
        if(ret == -1)
        {
                printf("有名管道创建失败\n");
                perror("myfifo");
                return -1;
        }
        else
        {
                printf("有名管道创建成功\n");
                fd = open("/home/czx/mkfifo",O_RDONLY);
                if(fd < 0)
                {
                        printf("打开管道错误\n");
                        return -2;
                }
                else
                {
                        while(1)
                        {
                                read_ret = read(fd,readBuff,20);
                                printf("读取到的字节数%d,内容为:%s\n",read_ret,readBuff);
                        }
                }
        }
        close(fd);
        return 0;
}
利用管道进行写数据:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
        char writeBuff[20];
        int fd;
        fd = open("/home/czx/mkfifo",O_WRONLY);
        if(fd < 0)
        {
                printf("打开管道错误\n");
                return -2;
        }
        else
        {
                while(1)
                {
                        gets(writeBuff);
                        write(fd,writeBuff,20);
                }
        }
        close(fd);
        return 0;
}
~       运行结果:
 
 
4.2特点
 
  有名管道  
 
 
  
  在磁盘上有这样一个文件  
  ls -l ->p  
 
 
  
  也是一个伪文件,在磁盘大小永久为 
  0  
 
 
  
  数据存在内核中有一个对应的缓冲区  
 
 
  
  半双工通信方式  
 
 
  
 4.3使用场景
 
  没有血缘关系的进程间通信  
 
 
  
 4.4创建方式
 
  命令: 
  mkfifo  
  管道名  
 
 
  
  函数: 
  mkfifo  
 
 
  
 4.5.fifo文件可以使用io函数进程操作
 
  open/close  
 
 
  
  read/write  
 
 
  
  不能执行 
  lseek 
  操作  
 
 



















