linux进程间通信—命名管道

命名管道
(一)命名管道不同于匿名管道指出是它提供了一个路径名,以FIFO的文件形式存在于文件系统中,这样即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交互数据。
命名管道(FIFO)和匿名管道(pipe)有一些特点是相同的,不一样的地方在于:
1.FIFO在文件系统中作为一个特殊的文件而存在,但是FIFO中的内容却存放在内存中。
2.当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便后面使用。
3.FIFO有名字,不相关的进程可以通过打开命名管道进行通信。
(二)命名管道的创建
1.所需头文件:

#include <sys/types.h>
#include <sys/stat.h>

2.函数:

int mkfifo(const char* pathname,mode_t mode);//功能是创建一个命名管道

3.参数:
(1)pathname:普通的路径名,也就是创建管道的名字。
(2)mode:文件的权限,与打开普通文件的open()函数的mode参数一样。
4.返回值:
(1)成功:0
(2)失败:-1
实例:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

int main()
{
  int ret;
  ret = mkfifo("myfifo",0666);
  if(ret == -1)
  {
    perror("mkfifo error");
  }
  return 0;
}

(三)命名管道的一些操作
1.后期的操作,把这个命名管道当作普通文件一样进行操作:open()、write()、read()、close()。但是和无名管道一样,需要考虑其阻塞特性。
下面验证的是open()的时候没有指定非阻塞标志(O_NONBLOCK)。
(1)

  • 当open()以只读方式打开FIFO时,要阻塞到某个进程为写而打开FIFO
  • 当open()以只写方式打开FIFO时,要阻塞到某个进程为读而打开FIFO
  • 总之就是一句话:只读等着只写,只写等着只读,都有两个条件都成立,才会往下执行。

read.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
  int fd;
  int ret;
  ret = mkfifo("myfifo1",0666);
  if(ret == -1)
  {
    perror("mkfifo error");
  }

  printf("before open\n");
  fd = open("myfifo1",O_RDONLY);
  if(fd<0)
  {
    perror("open error");
  }
  printf("after open\n");
  return 0;
}

write.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
  int fd;
  int ret;
  ret = mkfifo("myfifo1",0666);
  if(ret == -1)
  {
    perror("mkfifo error");
  }

  printf("before open\n");
  fd = open("myfifo1",O_WRONLY);
  if(fd<0)
  {
    perror("open error");
  }
  printf("after open\n");
  return 0;
}

结果动态演示:
在这里插入图片描述
当然也可以设置以可读可写方式打开,这样,调用open()函数时就不会阻塞了。
(2)假如FIFO中没有数据,调用read()函数从FIFO里读数据时,read()也会阻塞。这个特点和无名管道是一样的。
open_read.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
  int fd;
  int ret;
  ret = mkfifo("myfifo2",0666);
  if(ret == -1)
  {
    perror("mkfifo error");
  }

  printf("before open\n");
  fd = open("myfifo1",O_RDWR);
  if(fd<0)
  {
    perror("open error");
  }
  printf("after open\n");
  char buf[1024];
  printf("before read\n");
  read(fd,buf,sizeof(buf));
  printf("after read\n");
  return 0;
}

open_write.c

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

int main()
{
  int fd;
  int ret;
  ret = mkfifo("myfifo2",0666);
  if(ret == -1)
  {
    perror("mkfifo error");
  }

  printf("before open\n");
  fd = open("myfifo1",O_WRONLY);
  if(fd<0)
  {
    perror("open error");
  }
  printf("after open\n");

  char buf[1024] = "hello world";
  printf("before write\n");
  write(fd,buf,strlen(buf));
  printf("after write\n");
  return 0;
}

运行效果展示:
在这里插入图片描述
(3)通信过程中若写进程推出了,就算命名管道里没有数据,调用read()函数从FIFO里读数据时不阻塞;若写进程有重新运行,调用read()函数从FIFO里读数据时又恢复阻塞。
(4)通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到SIPIPE信号)退出。
(5)调用write()函数向FIFO里写数据,当缓冲区已满时,write()也会阻塞。
这两个管道和无名管道是一样的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值