IPC-管道

管道

  • 进程间通信的方式之一
  • 本质是对内核缓冲区的读写,存储在一个环形队列中
  • 管道对应的内核缓冲区的大小是固定的,默认为4KB
  • 管道分为读写两端,数据从写端进入管道,从读端流出管道
  • 管道中的数据只能读一次,相当于出队列
  • 管道是单工的,数据单向流动,从写端到读端
  • 对管道的读写操作都是阻塞的
    • 读管道:当管道中没有数据,读操作阻塞;有数据阻塞解除
    • 写管道:写满后,写操作阻塞;有空闲后,继续写入
IPC-管道

管道的分类

匿名管道:只能实现血缘关系的进程间通信

创建匿名管道
#include <unistd.h>
int pipe(int fd[2]);
  • 传出参数:

    • fd[0]—>读端
    • fd[1]—>写端
  • 返回值: 成功 0 ;失败 -1

匿名管道通信
  • 子进程执行shell命令ps aux ,父进程将结果显示到终端
//要关闭管道的一部分,形成唯一的单向流通线路
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>

int main(void)
{
	int fd[2];
	int ret = pipe(fd);
	if(ret == -1)
	{
		perror("pipe error!");
		return -1;
	}

	ret = fork();
	if(ret == 0) //children
	{
		//close read
		close(fd[0]);
		dup2(fd[1],STDOUT_FILENO);
		execlp("ps","ps","aux",NULL);
	}
	else if(ret > 0 )//parent
	{
		close(fd[1]);
		char buf[1024];

		while(1)
		{
			bzero(buf,sizeof(buf));
			ret = read(fd[0],buf,sizeof(buf));
			if(ret == 0)
				break;
			printf("%s-->%d\n",buf,ret);
		}
		close(fd[0]);
		wait(NULL);
	}
	else{
		perror("fork error");
		return -1;
	}


	return 0;
}

IPC-管道

有名管道

创建有名管道
  • 有名管道文件大小永远为 0,因为有名管道也是将数据存储到内存的缓冲区中
  • 有名管道可以在血缘关系的进程中使用,也可以在没有血缘关系的进程中使用
命令的方式
mkfifo 管道名
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const chra *pathname,mode_t mode);
  • pathname 创建有名管道的名字
  • mode 文件的权限
  • 最终权限mode & ~umask
  • 返回值: 成功 0;失败 -1
进程间通信
  • 需要通过open操作得到读写管道的文件描述符,如果读写端只有一端打开,进程会阻塞在open函数,知道另一个进程打开对应端。
//有名管道进行写操作
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(void)
{
    //创建有名管道
    int ret = mkfifo("./fifotest",0664);
    if(ret == -1)
    {
        perror("mkfifo error!");
        exit(-1);
    }
    printf("管道文件创建成功!\n");

    int ret_open = open("./fifotest",O_WRONLY);
    if(ret_open == -1)
    {
        perror("open fifo fail!");
        exit(-1);
    }

    //循环写入文件
    int i = 0;
    while(i<100)
    {
        char buf[4096]={0};
        sprintf(buf,"hello world %d",i+1);
        write(ret_open,buf,strlen(buf)); //如果只有写端,没有读端会阻塞的
        i++;
        sleep(1);
    }
    close(ret_open);
    exit(0);
}



/*
设置为非阻塞的形式
// 通过fcntl 修改就可以, 一般情况下不建议修改
// 管道操作对应两个文件描述符, 分别是管道的读端 和 写端

// 1. 获取读端的文件描述符的flag属性
int flag = fcntl(fd[0], F_GETFL);
// 2. 添加非阻塞属性到 flag中
flag |= O_NONBLOCK;
// 3. 将新的flag属性设置给读端的文件描述符
fcntl(fd[0], F_SETFL, flag);
// 4. 非阻塞读管道
char buf[4096];
read(fd[0], buf, sizeof(buf));

*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(void)
{

    int fd_r = open("./fifotest",O_RDONLY);
    if(fd_r == -1)
    {
        perror("open fifotest error!");
        exit(-1);
    }
    //循环读取
    
    char buf[4096];
    while (1)
    {
        memset(buf,0,sizeof(buf));
        int ret = read(fd_r,buf,sizeof(buf));
        if(ret == 0)
        {
            printf("已经读完,阻塞解除!\n");
            break;
        }
        printf("%s--->%d\n",buf,ret);
        
    }
    close(fd_r);

    exit(0);
}

pipe调用别的可执行文件

//fdfs_upload_file
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include "make_log.h"


int main(int argc,char *argv[])
{
      //create pipe
      int fd[2];
      int ret = pipe(fd);
      if(ret == -1)
      {
            LOG("pipe","create pipe error","ret = %d",ret);
            return -1;
      }

      ret = fork();
      if(ret == 0)//children
      {
            close(fd[0]);
            dup2(fd[1],STDOUT_FILENO);
            execlp("fdfs_upload_file","fdfs_upload_file","/etc/fdfs/client.conf",argv[1],NULL);
      }
      else if(ret > 0)//parent
      {
            close(fd[1]);
            char buf[1024] ;
            while(1)
            {
                  bzero(buf,sizeof(buf));
                  ret = read(fd[0],buf,sizeof(buf));
                  if(ret == 0)
                        break;
                  printf("%s",buf);
            }
            
            close(fd[0]);
            wait(NULL);
      }
      else{
            LOG("fork","fork error","fork ret = %d",ret);
            return -1;
      }
      LOG("interface","interface ok!","return 0");

      return 0 ;
}
上一篇:IPC_信号量(学习笔记)供参考


下一篇:2.域横向批量at&schtasks&impacke