进程间通信方式
传统进程间通信方式:
无名管道
有名管道
信号
system V的IPC对象:
共享内存(share memory)
消息队列(message queue)
信号灯集
BSD: 套接字
ipcs
ipcs -m :查询显示当前系统的共享内存
ipcs -q :查询显示当前系统的消息队列
ipcs -s :查询显示当前系统的信号灯集
ipcrm -m shmid:删除某个共享内存
ipcrm -q msgid:删除某个消息队列
ipcrm -s semid:删除某个信号灯集
IPC步骤:
key id
ftok ----> shm_get/msg_get/sem_get ----> shmmat/shmdt/shmctrl
msgctrl/msgsend/msgrecv
semctrl/semop
ftok函数
#include
#include
/**************************************************
*key_t ftok(const char *pathname, int proj_id);
*功能:得到一个key
*参数:
* pathname: 文件路径名
* proj_id: 子序号 INODE的低8位 1/2/3/4
*
*返回值:
* 成功返回 key
* 失败返回 -1
***************************************************/
【3】共享内存share memory
是一种通信效率最高的进程间通信方式,
进程间通信时直接访问内存,不需要进行数据的拷贝。
#include
#include
#include
步骤:
1. ftok
2. shmget
3. shmat
4. 进程间通信 fork
5. shmdt
6. shmctl
shmget函数
/*********************************************************
*int shmget(key_t key, size_t size, int shmflg);
*功能:创建/打开共享内存
*参数:
* key: IPC_PRIVATE 或 ftok的返回值
* size: 共享内存区大小
* shmflg: IPC_CREAT | 0666
*
*返回值:
* 成功返回: 共享内存段标识符 shmid
* 失败返回: -1
*********************************************************/
shmat函数
/*********************************************************
*void *shmat(int shmid, const void *shmaddr, int shmflg);
*功能:映射共享内存
*参数:
* shmid: 共享内存段标识符
* shmaddr: NULL (系统自动完成映射)
* shmflg:
0 读写
* SHM_RDONLY 只读
*返回值:
* 成功返回: 映射后的地址
* 失败返回: -1
*********************************************************/
shmdt函数
/*********************************************************
*int shmdt(const void *shmaddr);
*功能:解除共享内存的映射
*
*参数:
* shmaddr:映射后的地址
*
*返回值:
* 成功返回: 0
* 失败返回: -1
*********************************************************/
shmctl函数
/*********************************************************
*int shmctl(int shmid, int cmd, struct shmid_ds *buf);
*功能:共享内存控制函数
*参数:
* shmid: 共享内存段标识符
* cmd:
IPC_STAT:获取对象属性
IPC_SET: 设置对象属性
IPC_RMID:删除对象
* buf:
NULL (指定IPC_STAT/IPC_SET时用以保存/设置属性)
*
*返回值:
* 成功返回: 0
* 失败返回: -1
*********************************************************/
代码展示
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, const char *argv[])
{
key_t key;
key = ftok("/",1);
if (key == -1)
{
perror("ftok");
return -1;
}
printf("%#x\n",key);
int shmid = shmget(key,1024,IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return -1;
}
printf("shmid = %d\n",shmid);
system("ipcs -m");
char *p = shmat(shmid,NULL,0);
if (NULL == p)
{
perror("shmat");
goto xxx;
return -1;
}
pid_t pid;
pid = fork();
if (pid < 0)
{
perror("fork");
return -1;
}
else if (pid == 0)
{
while (1)
{
char buf[100] = {0};
fgets(buf,sizeof(buf),stdin);
strcpy(p,buf);
if (strncmp(buf,"quit",4) == 0)
break;
}
}
else{
waitpid(pid,NULL,WNOHANG);
while (1)
{
printf("p = %s\n",p);
sleep(1);
if (strncmp(p,"quit",4) == 0)
break;
}
}
int ret = shmdt(p);
if (ret == -1)
{
perror("shmdt");
goto xxx;
}
shmctl(shmid, IPC_RMID,NULL);
if (ret == -1)
{
perror("shmdt");
goto xxx;
}
xxx:
sleep(2);
char buf[32] = {0};
sprintf(buf,"ipcrm -m %d",shmid);
system(buf);
system("ipcs -m");
return 0;
}
【4】消息队列
#include
#include
#include
步骤:
1. ftok
2. msgget
3. 进程间通信
4. msgsnd
5. magrcv
6. msgctl
msgget函数
/*********************************************************
*int msgget(key_t key, int msgflg);
*功能:创建一个消息队列
*
*参数:
* key:ftok的返回值key
* msgflg:IPC_CREAT | 0666
*
*返回值:
* 成功返回: msgid
* 失败返回: -1
*********************************************************/
msgsnd函数
/*********************************************************
*int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
*功能:发送消息:将消息添加到消息队列
*
*参数:
* msqid:msgid
* msgp: &msg
struct msgbuf{
long mtype; //消息类型
char mtext[N]; //消息正文
}
struct msgbuf msg;
* msgsz:发送消息正文的字节数:sizeof(msg) - sizeof(long)
* msgflg:
0 : 阻塞
IPC_NOWAIT :非阻塞
*
*返回值:
* 成功返回: 0
* 失败返回: -1
*********************************************************/
msgrcv函数
/*********************************************************
*ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtype, int msgflg);
*功能:接收消息:从消息队列中去取消息
*
*参数:
* msqid:msgid
* msgp:&msg
struct msgbuf{
long mtype; //消息类型
char mtext[N]; //消息正文
}
struct msgbuf msg;
* msgsz:接收消息的字节数:sizeof(msg) - sizeof(long)
* msgtype:long mtype; //消息类型
* msgflg:
0 : 阻塞
IPC_NOWAIT :非阻塞
*
*返回值:
* 成功返回:接收到的消息的长度
* 失败返回:-1
*********************************************************/
msgctl函数
/*********************************************************
*int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*功能:消息队列控制函数
*
*参数:
* msqid:msgid
* cmd:
IPC_STAT:获取对象属性
IPC_SET: 设置对象属性
IPC_RMID:删除对象
* buf:
* NULL
*返回值:
* 成功返回
* 失败返回
*********************************************************/
代码展示
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct msgbuf{
long type;
char buf[100];
}msg_buf;
int main(int argc, const char *argv[])
{
key_t key;
key = ftok("/",'a');
if (key == -1)
{
perror("ftok");
return -1;
}
printf("%#x\n",key);
int msgid = msgget(key,IPC_CREAT | 0666);
if (msgid == -1)
{
perror("shmget");
return -1;
}
printf("shmid = %d\n",msgid);
system("ipcs -q");
pid_t pid;
pid = fork();
if (pid < 0)
{
perror("fork");
return -1;
}
else if (pid == 0)
{
while (1)
{
char buf[100]={0};
fgets(buf,sizeof(buf),stdin);
msg_buf msg;
msg.type = 100;
strcpy(msg.buf,buf);
msgsnd(msgid,&msg,sizeof(msg) - sizeof(long),0);
if (strncmp(buf,"quit",4) == 0)
{
int ret = msgctl(msgid, IPC_RMID,NULL);
if (ret == -1)
{
perror("megctl");
goto xxx;
}
break;
xxx:
sleep(2);
char buf[32] = {0};
sprintf(buf,"ipcrm -q %d",msgid);
system(buf);
system("ipcs -q");
}
}
}
else{
waitpid(pid,NULL,WNOHANG);
while (1)
{
msg_buf msg;
msgrcv(msgid,&msg,sizeof(msg)-sizeof(long),100,0);
if (strncmp(msg.buf,"quit",4)==0)
break;
printf("%s",msg.buf);
}
}
return 0;
}
【5】信号灯集
#include
#include
#include
步骤:
1. ftok
2. shmget
3. shmat
* 4. semget
* 5. semctl
6. 进程间通信
* 7. semop
* 8. semctl
5. shmdt
6. shmctl
semget函数
/*********************************************************
*int semget(key_t key, int nsems, int semflg);
*功能:创建一个信号灯集
*
*参数:
* key:IPC_PRIVATE 或 ftok的返回值
* nsems:信号灯集中信号灯的数目
* semflg:IPC_CREAT | 0666
*
*返回值:
* 成功返回: semid
* 失败返回: -1
*********************************************************/
semctl函数
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) */
};
/*********************************************************
*int semctl(int semid, int semnum, int cmd, .../*union semunarg*\);
*功能:信号灯集的控制函数
*
*参数:
* semid:semid
* semnum:要修改的信号灯编号
* cmd:
GETVAL:获取信号灯的值
SETVAL:设置信号灯的值
IPC_RMID:删除信号灯集
*
.../*union semun
*返回值:
* 成功返回: 0
* 失败返回: -1
*********************************************************/
semop函数
/*********************************************************
*int semop(int semid, struct sembuf *opsptr, size_t nops);
*功能:对信号灯执行P(-1) V(+1)操作
*
*参数:
* semid:semid
* opsptr:
struct sembuf{
short sem_num; //信号灯的编号
short sem_op;
// 0 等待,直到信号灯值变为0
// 1 V操作
// -1 P操作
short sem_flg;
// 0 阻塞
// IPC_NOWAIT 非阻塞
}
* nops:要操作的信号灯的个数
*
*返回值:
* 成功返回: 0
* 失败返回: -1
*********************************************************/
代码展示
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int main(int argc, const char *argv[])
{
key_t key;
key = ftok("/",1);
if (key == -1)
{
perror("ftok");
return -1;
}
printf("%#x\n",key);
int shmid = shmget(key,1024,IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return -1;
}
printf("shmid = %d\n",shmid);
system("ipcs -m");
int semid = semget(IPC_PRIVATE, 2,IPC_CREAT|0666);
if (semid < 0)
{
perror("semget");
return -1;
}
union semun sem0 = {0};
union semun sem1 = {1};
semctl(semid, 0, SETVAL,sem0);
semctl(semid, 1, SETVAL,sem1);
char *p = shmat(shmid,NULL,0);
if (NULL == p)
{
perror("shmat");
goto xxx;
return -1;
}
pid_t pid;
pid = fork();
if (pid < 0)
{
perror("fork");
return -1;
}
else if (pid == 0)
{
while (1)
{
struct sembuf sem;
sem.sem_num = 1;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid,&sem,1);
char buf[100] = {0};
fgets(buf,sizeof(buf),stdin);
strcpy(p,buf);
if (strncmp(buf,"quit",4) == 0)
break;
sem.sem_num = 0;
sem.sem_op = 1;
sem.sem_flg = 0;
semop(semid,&sem,1);
}
}
else{
while (1)
{
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid,&sem,1);
printf("p = %s",p);
if (strncmp(p,"quit",4) == 0)
{
wait(NULL);
break;
}
sem.sem_num = 1;
sem.sem_op = 1;
sem.sem_flg = 0;
semop(semid,&sem,1);
}
}
int ret = shmdt(p);
if (ret == -1)
{
perror("shmdt");
goto xxx;
}
shmctl(shmid, IPC_RMID,NULL);
if (ret == -1)
{
perror("shmdt");
goto xxx;
}
ret = semctl(semid,0|1,IPC_RMID);
if (ret < 0)
{
perror("semctl");
return -1;
}
xxx:
sleep(2);
char buf[32] = {0};
sprintf(buf,"ipcrm -m %d",shmid);
system(buf);
system("ipcs -m");
return 0;
}