linux进程间通信--管道通信

管道进程间通信

(1)无名管道
特点:
  只能用于具有亲缘关系进程间通信(具有亲缘关系的进程具有数据拷贝动作(复制父进程创建子进程))或者兄弟进程之间

  是一种单工的通信模式,具有固定的读端和写端

int pipe(int pipefd[2]);
 功能:创建一个无名管道
参数:
@pipefd 获取操作无名管道的文件描述符    pipefd[0]:读无名管道     pipefd[1]:写无名管道
返回值:
成功返回0,失败返回-1



示例如下:

void write_pipe(int fd)
{
  int ret;
  char buf[1024];

while(1)
{
  fgets(buf,sizeof(buf),stdin);
  buf[strlen(buf) - 1] = '\0';

  ret = write(fd,buf,strlen(buf));
  printf("write %d bytes!\n",ret);

  if(strcmp(buf,"quit") == 0){
    break;
  }
}

return;
}

void read_pipe(int fd)
{
  int ret;
  char buf[1024];

while(1)
{
  printf("read ....!\n");
  ret = read(fd,buf,sizeof(buf));
  buf[ret] = '\0';
  printf("Read %d bytes : %s\n",ret,buf);

if(strcmp(buf,"quit") == 0){
  break;
  }
}

return;
}

int main(int argc, const char *argv[])
{
  int ret;
  pid_t pid;
  int pipefd[2];

  ret = pipe(pipefd);
  if(ret < 0){
    perror("Fail to pipe");
    exit(EXIT_FAILURE);
  }

pid = fork();
if(pid < 0){
  perror("Fail to fork");
  exit(EXIT_FAILURE);
}

if(pid == 0){
  close(pipefd[1]);
  read_pipe(pipefd[0]);
}

if(pid > 0){
  close(pipefd[0]);
  write_pipe(pipefd[1]);
}

return 0;
}

功能:让父进程从键盘读入数据,然后写到无名管道,让子进程从无名管道中读取数据,然后输出,
如果输入"quit",则两个进程结束,功能比较简单


(2)管道读写规则
读端存在 ,写管道 ---->只要管道没有满,都可以写入数据到管道
读端不存在,写管道 ---->此时写管道没有意义,操作系统会发送SIGPIPE杀死写管道的进程

写端存在, 读管道 ---->此时管道中读取数据,管道中没有数据,读阻塞
写端不存在,读管道 ---->此时管道中读取数据,管道中没有数据,此时不阻塞,立即返回,返回值0

(3)有名管道
特点:

可以用于任意进程间通信,它是一种特殊的文件,在文件系统存在名字,
而文件中存放的数据是在内核空间,而不是在磁盘上

1.创建一个有名管道文件
int mkfifo(const char *pathname, mode_t mode);
@pathname 有名管道存在的路径
@mode 有名管道的权限
返回值:
成功返回0,失败返回-1

与FIFO相关的错误信息(主要如下)

EEXIST:参数filename所指定的文件已存在

EACCESS::参数filename所指定的目录无可执行权限

 

常用的用法:

if(access(FIFO,F_OK)==-1)

{

  if(mkfifo(FIFO,0666)<0)&&(errno!=EEXIST)

  {

    printf("cannot create fifo file\n");

    exit(1);

  }

}

2.打开有名管道文件

open

如果有名管道的一端以只读的方式打开,会阻塞,直到另一端以写(只写或读写)的方式打开
如果有名管道的一端以只写的方式打开,会阻塞,直到另一端以读(只读或读写)的方式打开


3.读写操作
read /write

4.关闭管道文件
close(fd);

 

示例如下:

a_fifo.c:

void read_fifo(int fd)
{
  int ret;
  char buf[1024];

while(1)
{
  printf("read ....!\n");
  ret = read(fd,buf,sizeof(buf));
  buf[ret] = '\0';

  printf("Read %d bytes : %s\n",ret,buf);

  if(strcmp(buf,"quit") == 0){
    break;
  }
}

return;
}

int main(int argc, const char *argv[])
{
  int ret;
  int fd;

if(argc < 2){
  fprintf(stderr,"Usage : %s <fifo>!\n",argv[0]);
  return -1;
}

ret = mkfifo(argv[1],0666);
  if(ret < 0 && errno != EEXIST){
    fprintf(stderr,"Fail to mkfifo %s : %s!\n",argv[1],strerror(errno));
    return -1;
  }

fd = open(argv[1],O_RDONLY);
if(fd < 0){
  fprintf(stderr,"Fail to open %s : %s!\n",argv[1],strerror(errno));
  return -1;
  }
printf("open success, fd : %d!\n",fd);

read_fifo(fd);

close(fd);

return 0;
}

 

 

b_fifi.c:

void write_fifo(int fd)
{
  int ret;
  char buf[1024];

while(1)
{
  fgets(buf,sizeof(buf),stdin);
  buf[strlen(buf) - 1] = '\0';

  ret = write(fd,buf,strlen(buf));
  printf("write %d bytes!\n",ret);

  if(strcmp(buf,"quit") == 0){
  break;
  }
}

return;
}

//./a.out fifo
int main(int argc, const char *argv[])
{
  int ret;
  int fd;

if(argc < 2){
  fprintf(stderr,"Usage : %s <fifo>!\n",argv[0]);
  return -1;
}

ret = mkfifo(argv[1],0666);
if(ret < 0 && errno != EEXIST){
fprintf(stderr,"Fail to mkfifo %s : %s!\n",argv[1],strerror(errno));
return -1;
}

fd = open(argv[1],O_WRONLY);
if(fd < 0){
  fprintf(stderr,"Fail to open %s : %s!\n",argv[1],strerror(errno));
  return -1;
}
printf("open success, fd : %d!\n",fd);

write_fifo(fd);

close(fd);

return 0;
}

功能如下:
 A进程向有名管道中写数据 , B进程从有名管道中读取数据 (A,B进程没有亲缘关系)

编译a_fifi.c 和b_fifi.c

 

gcc a_fifio.c -o a

gcc b_fifio.c -o b

并运行

a fifo

b fifo

 

 管道通信还是比较简单!

 

posted @ 2018-07-10 15:31  白伟碧一些小心得  阅读(293)  评论(0编辑  收藏  举报