linux学习笔记6 进程间通信(IPC)

1.管道方式通信(pipe)

个人理解是在内核开辟一块公共区域,将需要传递的信息放在里面进行通信,这块区域就像管道一样,但是管道只适用于有血缘关系的进程之间通信,并且一个父进程下只会建立一个管道,所有父子进程都能够与这一管道的读写两端连接。

函数pipe()创造一个管道,其函数原型为:int pipe(pipefd[2])。

其中pipefd是一个长度为2的数组,其中pipefd[0]代表的是管道读端的文件描述符,pipefd[1]代表的是管道写端的文件描述符。

返回值为0代表管道建立成功,返回值为-1代表错误。

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
int main()
{
	int fd[2];
	int res=pipe(fd);
	if (res==-1) return 0;
	pid_t pid=fork();
	if (pid==0){
		char a[]="hello !\n";
		write(fd[1], a, sizeof(a));
	}//子进程程序,将字符串“hello !\n”写入管道的写端
        else if (pid>0){
		char buf[20];
		int ret=read(fd[0], buf, sizeof(buf));
		if (ret>0)
			write(STDOUT_FILENO, buf, ret);
//STDOUT_FILENO是每个进程都有的文件描述符,对应数字是1,这个文件描述符就是输出到终端的作用。
	}//父进程程序,将管道中写入的内容先读到buf缓冲区中,再从缓冲区写到终端上。
	return 0;
}

注:对文件描述符的理解——每个进程都有一个文件描述符表,其中每个文件描述符表在开始都有三个固定值,0,1,2,其中0代表标准输入(宏定义:STDIN_FILENO),1代表标准输出(宏定义:STDOUT_FILENO),2代表标准错误(宏定义:STDERR_FILENO)。进程中每添加一个文件就会在文件描述符表上对应一个新数字,并且通过文件描述符表来使用文件。

管道读写中的情况罗列:

2.有名管道方式通信(fifo)

这种方式和pipe类似,但是可以在没有血缘关系的进程之间通信。

命名管道是一个伪文件,该文件的创建方式有两种:

1.通过命令创建:mkfifo 管道名

2.通过编程函数创建:int mkfifo(const char *pathname, mode_t mode );成功返回0,失败返回-1。

一旦创建了fifo文件,各个进程都可以打开这个文件进行文件的读写操作。

程序举例:实现一个进程向另一个进程传递信息的功能

首先创建一个fifo管道伪文件

输入命令:mkfifo myfifo  ,就得到一个myfifo的管道文件

然后建立两个独立进程,也就是两个拥有独立主函数的cpp文件:

负责写入的程序如下

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

using namespace std;

int main(int argc, char * argv[])
//argc存放的是入口参数的个数,argv指针指向的数组中存放具体参数。
//在常规情况下,没有额外的入口参数时,默认argc为1,argv[0]为程序名称。在这里这个主函数需要一个额外
//参数,就是fifo管道的文件名,所以这里的argc==2,argv[1]==“myfifo”。
{
	if (argc!=2){
		cout<<"there is error.\n";
		return 0;
	}
	int fd=open(argv[1], O_WRONLY);//这里打开管道时只打开了写通道,不可以进行读操作。
	int num=0;
	char buf[256];
	while (1){
		memset(buf, 0x00, sizeof(buf));//清除之前的缓存
		sprintf(buf, "count is %04d \n", num++);//合并字符串和变量
		write(fd, buf, strlen(buf));//将字符串写入管道中
		sleep(1);
	}
	close(fd);
}

负责读操作的程序如下:

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
using namespace std;

int main(int argc, char * argv[])
{
	if (argc!=2){
		cout<<"there is error\n";
		return 0;
	}
	int fd=open(argv[1], O_RDONLY);//打开管道文件只能进行读操作
	char buf[256];
	while (1){
		memset(buf, 0x00, sizeof(buf));
		read(fd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, strlen(buf));
	}
	close(fd);
}

分别编译两个程序之后,打开两个终端分别打开可执行文件

先打开读或者先打开写都没有关系。

3.文件映射

使用mmap函数

函数原型:

void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset);

返回:成功:返回创建的映射区首地址;失败:MAP_FAILED宏

参数:

addr: 建立映射区的首地址,由Linux内核指定。使用时,直接传递NULL

length: 欲创建映射区的大小

prot: 映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE

flags: 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)

   MAP_SHARED:  会将映射区所做的操作反映到物理设备(磁盘)上。

   MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。

fd: 用来建立映射区的文件描述符

offset: 映射文件的偏移(4k的整数倍)

猜你喜欢

转载自blog.csdn.net/qq_34489443/article/details/87855387