Linux_进程间通信之命名管道

1、命名管道

  • 命名管道的限制就是只能在具有共同祖先的进程间通信
  • 如果我们想在不相关的进程间交换数据,可以用FIFO文件来做这项工作,称为命名管道
  • 命名管道是一种特殊类型的文件

创建命名管道

(1)命令行方法

mkfifo filename

(2)程序里创建

int mkfifo(const char * filename, mode_t mode);
int main()
{
	mkfifo("file", 0644);
	return 0;
}

匿名管道与命名管道的区别

  • 匿名管道由pipe函数创建并打开
  • 命名管道用mkfifo函数创建,用open打开
  • FIFO与pipe之间唯一的区别在于创建和打开方式不同,其他语义相同

命名管道的打开规则

  • 如果当前操作是为读而打开FIFO时
    O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
    O_NONBLOCK enable:立刻返回成功
  • 如果当前操作是为写而打开FIFO时
    O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
    O_NONBLOCK enable:立刻返回失败,错误码ENXIO

命名管道实现文件拷贝

读源文件,写入命名管道

#include<iostream>
#include<stdio.h>
#include<errno.h>
#include<cstring>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)

using namespace std;

void mk_fifo()
{
	mkfifo("tp", 0644);
}

void rdfile_wrTofifo()
{
	int infd = open("file", O_RDONLY);
	if(infd == -1)
	{
		ERR_EXIT("open_file");
	}
	int outfd = open("tp", O_WRONLY);
	if(outfd == -1)
	{
		ERR_EXIT("open_tp");
	}
	char buf[SIZE] = {};
	int len;
	while((len = read(infd, buf, SIZE)) > 0)
	{
		write(outfd, buf, len);
	}
	close(infd);
	close(outfd);
}

int main()
{
	mk_fifo();
	rdfile_wrTofifo();
	return 0;
}

读命名管道,写入目标文件

#include<iostream>
#include<stdio.h>
#include<errno.h>
#include<cstring>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)

using namespace std;

void rdfifo_wrTofile()
{
	int infd = open("tp", O_RDONLY);
	if(infd == -1)
	{
		ERR_EXIT("open_tp");
	}
	int outfd = open("file.bak", O_WRONLY|O_CREAT|O_TRUNC, 0644);
	if(outfd == -1)
	{
		ERR_EXIT("open_file_bak");
	}
	char buf[SIZE] = {};
	int len;
	while((len = read(infd, buf, SIZE)) > 0)
	{
		write(outfd, buf, len);
	}
	close(infd);
	close(outfd);
	unlink("tp");
}

int main()
{
	rdfifo_wrTofile();
	return 0;
}

命名管道实现server/client通信

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)

using namespace std;

void mk_fifo()
{
	umask(0);
	if(mkfifo("mypipe", 0644) < 0)
	{
		ERR_EXIT("mypipe");
	}
}

void serverPipe()
{
	int rfd = open("mypipe", O_RDONLY);
	if(rfd < 0)
	{
		ERR_EXIT("open_rfd");
	}
	char buf[SIZE] = {};
	while(1)
	{
		cout<<"Waiting......"<<endl;
		size_t len = read(rfd, buf, SIZE);
		if(len == 0)
		{
			cout<<"client quit!......"<<endl;
			unlink("mypipe");
			exit(EXIT_SUCCESS);
		}
		else if(len > 0)
		{
			buf[len-1] = '\0';
			cout<<buf<<endl;
		}
		else
		{
			ERR_EXIT("read_rfd");
		}
	}
	close(rfd);
}

int main()
{
	mk_fifo();
	serverPipe();
	return 0;
}
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)

using namespace std;

void clientPipe()
{
	int wfd = open("mypipe", O_WRONLY);
	if(wfd < 0)
	{
		ERR_EXIT("open_wfd");
	}
	char buf[SIZE] = {};
	while(1)
	{
		cout<<"Enter#";
		fflush(stdout);
		size_t len = read(0, buf, SIZE);
		if(len <= 0)
		{
			ERR_EXIT("read_wfd");
		}
		else if(len > 0)
		{
			buf[len] = '\0';
			write(wfd, buf, strlen(buf));
		}
	}
	close(wfd);
}

int main()
{
	clientPipe();
	return 0;
}

2、其他几种进程间通信方式

System V 共享内存

共享内存是最快的IPC形式,一旦这样的内存映射到共享他的进程的地址空间,这些进程间数据传递不再涉及内核,进程不再通过执行进入内核的系统调用来传递数据
在这里插入图片描述
System V 消息队列

  • 消息队列提供了一个从一个进程向另一个进程发送一块数据的方法
  • 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值
  • IPC资源必须删除,否则不会自动清除。System V IPC资源的生命周期随内核

System V 信号量

信号量主要用于同步和互斥

  • 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程竞争使用这些资源,进程的这种竞争关系称为进程的互斥
  • 系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源
  • 在进程中涉及到互斥资源的程序段称为临界区
  • IPC资源必须删除,否则不会自动清除。System V IPC资源的生命周期随内核
发布了72 篇原创文章 · 获赞 25 · 访问量 7334

猜你喜欢

转载自blog.csdn.net/qq_41245381/article/details/104002788