目录
一、system V IPC对象
IPC对象包括:共享内存、消息队列、信号灯集
每个IPC对象由唯一ID
IPC创建后一直存在,直到显式删除(程序中注意及时关闭)
每个IPC对象有个关联的key
ipcs:查看IPC对象
所有的IPC对象只能通过用户显式地进行删除
1、key值地获取
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
参数:
pathname:任意路径
proj_id:任意字符
返回值:
成功返回key值,失败返回-1
2、共享内存
共享内存是进程间通信效率最高的一种通信机制
使用共享内存流程:
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
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、访问共享内存
4、取消映射 -- shmdt()
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
参数:
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:删除共享内存,第三个参数填空
返回值:
成功返回0,失败返回-1
2、消息队列
消息队列的使用流程:
1、创建、打开消息队列 -- msgget
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
参数:
key:通过ftok得到的key值或者使用IPC_CREAT
shmflg:创建消息队列的权限,一般填 0664 |IPC_CREAT
返回值:
成功返回消息队列ID,失败返回-1
2、发送消息 -- msgsnd
#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:消息结构体中正文内容的大小
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)
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:接收消息结构体中正文内容的大小
msgflg: 0 -- 以阻塞方式发送消息
IPC_NOWAIT -- 以阻塞方式发送消息
返回值:
成功返回0,失败返回-1
4、删除消息队列 -- msgctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
例:
msgctl(msgid)
练习:使用两个进程,两个进程间互相收发数据
A:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.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[])
{
MSG msg;
int ret = 0;
char buf[64] = {0};
key_t key = ftok(".", 'i'); //获取key值
if(key < 0)
{
perror("ftok");
exit(-1);
}
int msgid = msgget(key, 0664 | IPC_CREAT); //创建、打开消息队列得到msgid
if(msgid < 0)
{
perror("msgget");
exit(-1);
}
while(1)
{
memset(&msg, 0, sizeof(MSG)); //清空结构体
msg.mtype = typeA;
printf("input>>");
fgets(buf, 64, stdin);
strcpy(msg.mtext, buf);
ret = msgsnd(msgid, &msg, LEN, 0);
if(ret < 0)
{
perror("msgsnd");
exit(-1);
}
if(strcmp(buf, "quit\n") == 0)
{
printf("bye~ \n");
break;
}
memset(&msg, 0, sizeof(MSG)); //清空结构体
ret = msgrcv(msgid, &msg, LEN, typeB, 0);
if(ret < 0)
{
perror("msgrcv");
exit(-1);
}
if(strcmp(msg.mtext, "quit\n") == 0)
{
printf("bye~\n");
msgctl(msgid, IPC_RMID, NULL);
break;
}
printf("recv:%s",msg.mtext);
}
return 0;
}
B:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.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[])
{
MSG msg;
int ret = 0;
char buf[64] = {0};
key_t key = ftok(".", 'i'); //获取key值
if(key < 0)
{
perror("ftok");
exit(-1);
}
int msgid = msgget(key, 0664 | IPC_CREAT); //创建、打开消息队列得到msgid
if(msgid < 0)
{
perror("msgget");
exit(-1);
}
while(1)
{
memset(&msg, 0, sizeof(MSG)); //清空结构体
ret = msgrcv(msgid, &msg, LEN, typeA, 0);
if(ret < 0)
{
perror("msgrcv");
exit(-1);
}
if(strcmp(msg.mtext, "quit\n") == 0)
{
printf("bye~\n");
msgctl(msgid, IPC_RMID, NULL);
break;
}
printf("recv:%s",msg.mtext);
memset(&msg, 0, sizeof(MSG)); //清空结构体
msg.mtype = typeB;
printf("input>>");
fgets(buf, 64, stdin);
strcpy(msg.mtext, buf);
ret = msgsnd(msgid, &msg, LEN, 0);
if(ret < 0)
{
perror("msgsnd");
exit(-1);
}
if(strcmp(buf, "quit\n") == 0)
{
printf("bye~ \n");
break;
}
}
return 0;
}
3、信号灯集
(1)semget()
创建信号灯集
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
参数:
key:产生信号灯id需要使用的键值,可以用IPC_PRIVATE 或 ftok来获取
semflg:标志位,设置信号灯权限
IPC_CREAT:创建新的信号灯
返回值:
成功返回信号灯id号,错误返回-1
(2)semctl()
设置信号灯初值(或其他操作:比如 删除信号灯)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
参数:
semiid:信号灯标识id
semnum:
cmd:控制命令
IPC_RMID:删除信号灯
IPC_SET: 设置信号灯相关属性
...: 可变参数 如果第三个参数是 IPC_RMID 则第四个参数可以不传
如果第三个参数是 IPC_SET 则需要传递第四个参数.
参数类型是一个共用体:
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
返回值:
成功根据cmd值的不同而返回不同的值,失败反返回-1
(3)semop()
实现P、V操作
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
参数:
semid:信号灯标识id
sops:信号灯操作结构体数组首地址
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
}
sem_num:信号灯编号
sem_op:
1:表示V操作(释放资源)
-1:表示P操作(申请资源)
sem_flg:通常为0表示阻塞等待
nsops:表示需要控制多少个信号灯
返回值:
成功返回0,失败返回-1