1.进程间通讯
有名和无名管道
(1)有名管道
mkfifo
(2)无名管道:只能用于既具有亲缘关系的进程间通讯
pipe
(3)信号
在软件层次上的中断模拟
2.system V IPC 对象
ipcs:查看IPC对象
私有的共享内存,key为0,
所有的IPC对象,只能通过用户显式的进行删除,手动申请,手动释放
(1)共享内存
共享内存是所有进程间通信方式中效率最高的一种。
使用共享内存流程:🥶🥶🥶🥶🥶🥶🥶🥶
1.创建或者打开共享内存 --shmget()
2.映射共享内存 --shmat()
3.访问共享内存(读写)
4.取消映射 --shmdt()
5.删除共享内存 ---shmctl()
0.key值的获取
#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);
参数:
pathname:任意路径
proj_id:任意字符
字符串与整数的低八位运算,生成的key值,只有相同的路径与字符才能生成一样的key值。
eg: key_t key=ftok(".",'s');返回值:
成功返回key值,失败返回-1
1.创建或者打开共享内存 --shmget()
#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
参数:
key:通过ftok得到,或者通过宏IPC_PRIVATE(创建私有的共享内存,只有亲缘进程可以使用)
size:共享内存的大小
shmflg:创建共享内存权限,一般填0664 | IPC_CREAT返回值:
成功,得到共享内存ID,失败返回-1
eg:
int shmid = shmget(key,1024,IPC_CREAT | 0664)
2.映射共享内存 --shmat()
#include <sys/types.h>
#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid:共享内存ID
shmaddr:填NULL,表示系统自动分配
shmflg:SHM_RDONLY --只读
0 --读写
返回值:
成功返回映射地址,失败返回(void *)-1
3.访问共享内存(读写)
scanf("%d",(char *)addr);
fgets((char *)addr,1024,stdin);put((char *)addr);
4.取消映射 --shmdt()
#include <sys/types.h>
#include <sys/shm.h>int shmdt(const void *shmaddr);
参数:
要取消映射的地址;
返回值:
成功返回0,失败返回-1
5.删除共享内存 ---shmctl()
#include <sys/ipc.h>
#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:共享内存的ID号
cmd:操作共享内存的指令
IPC_STAT:获取共享内存的信息,存于第三个参数,结构体指针
IPC_SET:设置共享内存信息,通过第三个参数,结构体指针
IPC_RMID:删除共享内存,第三个参数填NULL(连接数(映射数)为0的情况下才能删除)返回值:
成功返回0,失败返回-1
练习:使用两个进程,一个进程向共享内存输入数据,另外一个内存输出数据
write:
/*===============================================
* 文件名称:shmget.c
* 创 建 者:
* 创建日期:2022年08月11日
* 描 述:
================================================*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
key_t key=ftok(".",'p');//生成key值
if(key<0)
{
perror("ftok");
return -1;
}
int shmid = shmget(key,1024,0664 | IPC_CREAT);//生成共享空间,记录id
if(shmid<0)
{
perror("shmget");
return -1;
}
void *addr =shmat(shmid,NULL,0);映射
if(addr==(void *)-1)
{
perror("shmat");
exit(-1);
}
//addr=(char *)addr;
memset(addr,0,1024); //清空缓存
while(1)
{
scanf("%s",(char *)addr); //键盘输入
sleep(1);
}
int ret = shmdt(addr); //删除映射
if(ret<0)
{
perror("shmdt");
exit(-1);
}
int ret1=shmctl(shmid,IPC_RMID,NULL);//关闭共享内存
if(ret1<0)
{
perror("shmctl");
exit(-1);
}
return 0;
}
read:
/*===============================================
* 文件名称:shmget.c
* 创 建 者:
* 创建日期:2022年08月11日
* 描 述:
================================================*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
key_t key=ftok(".",'p');//生成key值
if(key<0)
{
perror("ftok");
return -1;
}
int shmid = shmget(key,1024,0664 | IPC_CREAT);//创建共享内存
if(shmid<0)
{
perror("shmget");
return -1;
}
void *addr =shmat(shmid,NULL,0);//映射
if(addr==(void *)-1)
{
perror("shmat");
exit(-1);
}
while(1)
{
puts((char *)addr);//从共享内存输出
sleep(1);
}
int ret = shmdt(addr);//取消映射
if(ret<0)
{
perror("shmdt");
exit(-1);
}
return 0;
}
(2)消息队列
消息队列的使用流程
1.创建、打开消息队列 --msgget(0)
2.发送消息 --msgsnt()
3.接收消息 --msgrcv()
4.删除消息队列 --msgctl()
1.创建、打开消息队列 --msgget()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>参数:
key:通过ftok得到的key值,或者使用IPC_PRIVATE创建私有消息队列
msgflg: 创建消息队列权限,一般填0664 | IPC_CREAT
返回值:
成功返回消息队列ID,失败返回-1eg:
int msgid=msgget(IPC_PRIVATE,0664);//只能是创建,之前不会存在
2.发送消息 --msgsnt()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msqid:消息队列ID
msgp:与发送消息相关的结构体的首地址
msgsz:消息结构体中,正文内容的大小(n)
msgflg:发送消息的方式
填0--表示以阻塞方式发送消息
IPC_NOWAIT--不阻塞方式送返回值:
成功返回0,失败返回-1
用法:
#define LEN (sizeof(MSG)-sizeof(long) )// 第三个参数
typedef struct msgbuf
{
long mtype;
char mtext[64];//大小自己填
}MSG;
MSG msg;//第二个参数
char buf[64]={0};
msg.mtype=100;
fgets(buf,64,stdin);
strcpy(msg.mtext,buf);
msgsnd(msgid,&msg,LEN,0);
自己封装结构体
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
3.接收消息 --msgrcv()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
msqid:消息队列ID
msgp:与接收消息相关的结构体的首地址
msgsz:消息结构体中,正文内容的大小(n)
msgtyp:接收的消息队列的类型,在结构体中定义 🎆🎉🎉🎉
msgflg:发送消息的方式
填0--表示以阻塞方式接收消息
IPC_NOWAIT--不阻塞方式接收返回值:
成功返回0,失败返回-1
用法:#define LEN (sizeof(MSG)-sizeof(long) )// 第三个参数
typedef struct msgbuf
{
long mtype;
char mtext[64];//大小自己填
}MSG;
MSG msg;//第二个参数
char buf[64]={0};
msg.mtype=100;
fgets(buf,64,stdin);
strcpy(msg.mtext,buf);
msgsnd(msgid,&msg,LEN,0);
自己封装结构体
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
4.删除消息队列 --mesgctl()
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
shmid:共享内存的ID号
cmd:操作共享内存的指令
IPC_STAT:获取共享内存的信息,存于第三个参数,结构体指针
IPC_SET:设置共享内存信息,通过第三个参数,结构体指针
IPC_RMID:删除共享内存,第三个参数填NULL(连接数(映射数)为0的情况下才能删除)返回值:
成功返回0,失败返回-1
练习:使用两个进程,两个进程间互相收发信息
read:
/*===============================================
* 文件名称:read_msg.c
* 创 建 者:
* 创建日期:2022年08月11日
* 描 述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
#define LEN (sizeof(MSG)-sizeof(long))
#define typeA 100
#define typeB 200
typedef struct msgbuf
{
long mtype;
char mtext[64];
}MSG;
int main(int argc, char *argv[])
{
key_t key=ftok(".",'p');//创建key
if(key<0)
{
perror("ftok");
}
int msgid=msgget(key,0664 | IPC_CREAT);//创建消息队列
if(msgid<0)
{
perror("msgget");
exit(-1);
}
MSG msg; //定义消息队列结构体变量
char buf[64]={0};
while(1)
{
memset(&msg,0,sizeof(MSG)); //清空结构体
msgrcv(msgid,&msg,LEN,typeA,0);//接收数据A
if(strcmp(msg.mtext,"quit\n")==0)
{
printf("progream end\n");
msg.mtype=typeB; //定义结构体类型
strcpy(msg.mtext,"quit\n");//发送quit给对方
msgsnd(msgid,&msg,LEN,0);//发送数据
break;
}
printf("recv:%s",msg.mtext); //打印
msg.mtype=typeB; //定义结构体类型
printf("input:\n");
fgets(buf,64,stdin); //获取数据
strcpy(msg.mtext,buf); //拷贝数据
msgsnd(msgid,&msg,LEN,0);//发送数据B
}
int ret=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
if(ret<0)
{
perror("msgctl");
exit(-1);
}
return 0;
}
write:
/*===============================================
* 文件名称:write_msg.c
* 创 建 者:
* 创建日期:2022年08月11日
* 描 述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
#define LEN (sizeof(MSG)-sizeof(long))
#define typeA 100
#define typeB 200
typedef struct msgbuf
{
long mtype;
char mtext[64];
}MSG;
int main(int argc, char *argv[])
{
key_t key=ftok(".",'p');//创建key
if(key<0)
{
perror("ftok");
}
int msgid=msgget(key,0664 | IPC_CREAT);//创建消息队列
if(msgid<0)
{
perror("msgget");
exit(-1);
}
MSG msg; //定义消息队列结构体变量
char buf[64]={0};
while(1)
{
msg.mtype=typeA; //定义结构体类型
printf("input:\n");
fgets(buf,64,stdin); //获取数据
strcpy(msg.mtext,buf); //拷贝数据
msgsnd(msgid,&msg,LEN,0);//发送数据A
memset(&msg,0,sizeof(MSG)); //清空结构体
msgrcv(msgid,&msg,LEN,typeB,0);//接收数据B
if(strcmp(msg.mtext,"quit\n")==0)//判断是否接收到quit
{
printf("progream end\n");
msg.mtype=typeA; //定义结构体类型
strcpy(msg.mtext,"quit\n");//发送quit给对方
msgsnd(msgid,&msg,LEN,0);//发送数据
break;
}
printf("recv:%s",msg.mtext);
}
int ret=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
if(ret<0)
{
perror("msgctl");
exit(-1);
}
return 0;
}