文章目录
背景
匿名管道有一个缺点,就是只能血缘间通信,而我们想要让两个毫不相干的进程进行通信,就要用到命名管道,
🚩存储
要两个毫不相干的进程通信,首先要看到同一个管道文件,命名管道如何做到的呢?同一路径下的同一文件名,文件路径具有唯一性
所以,命名管道存储在文件系统中,有自己的文件路径和inode,但是不会向磁盘中刷数据,数据传输发生在内存级缓冲区中,
所以,纯内存级缓冲区的通信方法有:
匿名管道,共享内存,消息队列
建立命名管道
🚩命令行创建
1,命名管道可以直接在命令行创建:
mkfifo "管道名"

可以看到我创建了一个管道,向里面写入!

可以看到卡住了,那是因为卡在文件缓冲区了,我没有读取

并且我们查看文件大小,发现还是0,说明没刷盘,读取之后结束
删除管道用unlink, 比如这里
unlink myfile
🚩mkfifo函数实现通信
函数:
int mkfifo(const char *filename,mode_t mode);
用函数实现两个进程通信
头文件:封装类,完成命名管道初始化和清理
c
#include<iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#define FIFO_FILE "./myfile"
#define MODE 0664
enum{
FIFO_CREAT_FILE=1,
FIFO_DELETE_FILE,
FIFO_OPEN_FILE
};
class Init{
public:
Init()
{
int n=mkfifo(FIFO_FILE,MODE);
if(n==-1)
{
perror("mkfifo");
exit(FIFO_CREAT_FILE);
}
}
~Init()
{
int m=unlink(FIFO_FILE);
if(m==-1)
{
perror("unlink");
exit(FIFO_DELETE_FILE);
}
}
};
==读端:打开文件即可,要是写端没准备好,我们还需要等写端打开,==不断写入,如果x=0,说明写端关闭了,那我也关闭
c
#include "commen.h"
using namespace std;
int main()
{
Init it;
int fd=open(FIFO_FILE,O_RDONLY); //读端得等写端打开文件
cout<<"server ready done"<<endl;
if(fd==-1)
{
perror("open");
exit(FIFO_OPEN_FILE);
}
while(true)
{
char buffer[1024]={0};
int x=read(fd,buffer,sizeof(buffer));
if(x>0)
{
buffer[x]=0;
cout<<"client say:"<<buffer<<endl;
}
else if(x==0)
{
printf("client quit! me too! string errno %s,errno %d",strerror(errno),errno);
break;
}
else{
break;
}
}
return 0;
}
写端:打开文件,从键盘上获取字符串,写入文件
c
#include "commen.h"
using namespace std;
int main()
{
int fd=open(FIFO_FILE,O_WRONLY);
if(fd<0)
{
perror("open");
exit(FIFO_CREAT_FILE);
}
cout<<"client ready done"<<endl;
string line;
while(true)
{
cout<<"please enter:"<<endl;
getline(cin,line);
write(fd,line.c_str(),line.size());
}
close(fd);
return 0;
}

共享内存
🚩原理

🚩操作系统在物理内存中开辟一块物理内存,供两个进程交流,
操作系统中肯定有很多共享内存,操作系统肯定要管理,先描述再组织
要释放一个共享内存,先去关联再释放
🚩注意:
1,共享内存没有同步机制
2,共享内存通信速度最快(因为他拷贝最少)
3,共享内存数据都由用户自己控制
上代码:
shmget
🚩int shmget(key_y key , size_t size , int shmflg);
int 返回共享内存标识符
key:具有唯一性,保证进程能找到
size:共享内存大小
🚩shmflg:如何设置共享内存,O_CREAT没有就创建,有就打开
O_CREAT | O_EXIT,没有就创建,有返回错误
O_EXIT 不单独使用
🚩key 和 shmid(shmget返回值)区别
key:操作系统内标定唯一性
shmid:只在你的进程,用来表示资源唯一性
学习key
1,key 在内核中要具有唯一性,方便进程找到
2,第一个进程设置key,第二个进程拿着相同的key就能找到相同位置
3,key存在哪里?共享内存结构体中
🚩4,key其实类似路径 它怎么来的 ?函数
key_t ftok(const char* pathname, int proj_id id);
pathname是用户自己定义的路径/home/jib,id也是用户自己指定的
共享内存生命周期是随内核的,也就是用户不关闭,共享内存会一直存在,除非内核重启
🚩共享内存查看: ipcs -m
🚩共享内存删除:ipcrm -m shmid

nattch,表示哪个进程关联到此共享内存
shmat
🚩void *shmat(int shmid, const void *shmaddr, int shmflg);
🚩功能:将共享内存关联到进程中,,
shmid:共享内存的标识符
shmaddr:一般设置nullptr,核心自动选择地址
shmflg: 设置0 读写权限
shmdt
🚩 int shmdt(const void *shmaddr);
🚩功能:将进程去关联
shmaddr 共享内存起始地址
注意去关联,不代表释放共享内存
shmctl
功能:控制共享内存
🚩int shmctl(int shmid, int cmd, struct shmid_ds *buf);
cmd有3个动作

🚩实现共享内存
共享内存没有同步机制,也就是我们写入时,不会自动清理缓存区,就会一直打印重复数据
所以我们加了管道,通知读端
commen.hpp
c
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/shm.h>
using namespace std;
//共享内存给的是4096整数倍字节大小,
//就算定义 4097,给你的其实是4096*2,但是你访问4098又会报错
const int size=4096;
const string pathname="/home/jib";
const int proj_id = 0x6666;
key_t GetKey()
{
int k=ftok(pathname.c_str(),proj_id);
if(k<0)
{
perror("ftok");
exit(1);
}
printf("ftok success! key is 0x%x\n", k);
return k;
}
int GetShareMemHelper(int flag)
{
key_t k=GetKey();
int shmid=shmget(k,size,flag);
if(shmid<0)
{
perror("shmget");
exit(2);
}
printf("shmget success : %d",k);
return shmid;
}
int Createshm()
{
return GetShareMemHelper(IPC_CREAT| 0666);
}
int Getshm()
{
return GetShareMemHelper(IPC_CREAT|0666);
}
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#define FIFO_FILE "./myfile"
#define MODE 0664
enum{
FIFO_CREAT_FILE=1,
FIFO_DELETE_FILE,
FIFO_OPEN_FILE
};
class Init{
public:
Init()
{
int n=mkfifo(FIFO_FILE,MODE);
if(n==-1)
{
perror("mkfifo");
exit(FIFO_CREAT_FILE);
}
}
~Init()
{
int m=unlink(FIFO_FILE);
if(m==-1)
{
perror("unlink");
exit(FIFO_DELETE_FILE);
}
}
};
c
#include "commen.hpp"
#include "log.hpp"
using namespace std;
int main()
{
Log log;
Init init;
int shmid=Createshm();
char* shmaddr=(char*)shmat(shmid,nullptr,0);
int fd=open(FIFO_FILE,O_CREAT|O_RDONLY);
log(Info,"server open success");
if(fd<0)
{
log(Fetal,"error string : %s,error :%d",strerror(errno),errno);
exit(FIFO_CREAT_FILE);
}
struct shmid_ds shmds;
while(true)
{
char c;
size_t s=read(fd,&c,1);
if(s<0)
break;
else if(s==0)
break;
cout<<"Client Say:"<<shmaddr<<endl;
//sleep(1);
shmctl(shmid, IPC_STAT, &shmds);
cout << "shm size: " << shmds.shm_segsz << endl;
cout << "shm nattch: " << shmds.shm_nattch << endl;
printf("shm key: 0x%x\n", shmds.shm_perm.__key);
cout << "shm mode: " << shmds.shm_perm.mode << endl;
}
shmdt(shmaddr);
shmctl(shmid,IPC_RMID,nullptr);
close(fd);
return 0;
}
c
#include "commen.hpp"
#include "log.hpp"
using namespace std;
int main()
{
Log log;
int shmid=Getshm();
char* shmaddr=(char*)shmat(shmid,nullptr,0);
int fd=open(FIFO_FILE,O_CREAT| O_WRONLY,MODE);
if(fd<0)
{
log(Fetal,"error string :%s,errno :%d",strerror(errno),errno);
exit(FIFO_OPEN_FILE);
}
while(true)
{
cout<<"please enter :";
fgets(shmaddr,4096,stdin);
write(fd,"c",1);
}
shmdt(shmaddr);
return 0;
}
实现两个进程通信