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的整数倍)