ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

IPC-管道

2021-12-23 14:02:43  阅读:160  来源: 互联网

标签:IPC int ret 管道 fd include buf


管道

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

管道的分类

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

创建匿名管道
#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;
}

ps aux

有名管道

创建有名管道
  • 有名管道文件大小永远为 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,int,ret,管道,fd,include,buf
来源: https://blog.csdn.net/weixin_42478102/article/details/122105669

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有