IPC进程间通讯
使用命令ipcs可以查看IPC的对象。
ftok
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:转换pathname和proj_id为一个key值
参数:
pathname:指定文件的名字
proj_id:一个整数,这个整数的低8位不能为0
返回值:
成功 key值返回
-1 失败 errno被设置
1.第一步,获取一个键值。
2. 第二步,通过键值获取一块内存,将这块内存的id返回。
3. 第三部,通过内存id来操作这块内存。
代码示例
- ftok.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
int main(void){
key_t key;
//获取键值
key=ftok("hello",32);
if(key==-1){
perror("ftok");
return 1;
}
printf("key=%d\n",key);
return 0;
}
- 执行结果
消息队列
通过键值获取一块内存,将这块内存的id返回,需要使用到msgget获取内核内存的id。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
功能:获取一个消息队列的id
参数:
key:fotk(3)获取到的键值
msgflg:
IPC_CREAT:
IPC_EXCL:
mode: 指定了消息队列的权限
返回值:
-1 失败 errno被设置
成功返回消息队列的id
代码示例
通过键值获取消息队列的id
- msgget.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(void){
key_t key;
//获取键值
key=ftok("hello",31);
if(key==-1){
perror("ftok");
return 1;
}
printf("key=%x\n",key);
//通过键值获取消息队列的id
int msqid=msgget(key,IPC_CREAT|0664);
if(msqid==-1){
perror("msgget");
return 2;
}
printf("msgqid=%d\n",msqid);
return 0;
}
- 执行结果
向消息队列发送消息和接收消息
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:指向struct msgbuf类型的变量的指针
msgsz:是mtext的长度
msgflg:
IPC_NOWAIT 在空间不够的情况下,非阻塞等待,立即返回错误
0 空间不够的情况下,等待空间充足才解除阻塞
返回值:
0 成功
-1 失败 errno被设置
msgrcv
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz,\
long msgtyp,int msgflg);
功能:从消息队列中获取消息
参数:
msqid:指定了消息队列的id
msgp:指向了获取到的消息
msgsz:是mtext的长度
msgtyp:消息的类型
msgflg:
IPC_NOWAIT:如果消息队列中没有消息,立即返回
0:如果消息队列中没有消息,阻塞等待
返回值:
-1 错误 errno被设置
获取到的消息体的字节数
代码示例
将一个消息放入消息队列中。
- processA.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct msgbuf{
long mtype;
char mtext[256];
}msgbuf_t;
int main(void){
key_t key;
msgbuf_t mb;//消息类型的变量
//获取key值
key=ftok("hello",31);
if(key==-1){
perror("ftok");
return 1;
}
//获取消息队列的id
int msqid=msgget(key,IPC_CREAT|0664);
if(msqid==-1){
perror("msgget");
return 2;
}
//初始化消息
mb.mtype=3;/*must be >0*/
strcpy(mb.mtext,"this is test\n");
//向消息队列中写入消息
int s=msgsnd(msqid,&mb,strlen(mb.mtext)+1,0);
if(s==-1){
perror("msgsnd");
return 3;
}
return 0;
}
从消息队列中获取消息并显示
- processB.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct msgbuf{
long mtype;
char mtext[256];
}msgbuf_t;
int main(void){
key_t key;
msgbuf_t mb;//消息类型的变量
//获取key值
key=ftok("hello",31);
if(key==-1){
perror("ftok");
return 1;
}
//获取消息队列的id
int msqid=msgget(key,IPC_CREAT|0664);
if(msqid==-1){
perror("msgget");
return 2;
}
//从消息队列中获取消息
int s=msgrcv(msqid,&mb,256,3,0);
if(s==-1){
perror("msgrcv");
return 3;
}
printf("%s",mb.mtext);
return 0;
}
- 执行结果
共享内存
根据键值获取共享内存的id,通过shmget获取共享内存id。
int shmget(key_t key, size_t size, int shmflg);
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:
参数:
key:ftok(3)返回的键值
size:指定了共享内存的尺寸
shmflg:
IPC_CREAT:指定创建共享内存段
IPC_EXCL:
mode:
返回值:
-1 错误
返回共享内存段的id
将共享内存映射到进程的虚拟地址空间中,使用shmat
shmat(2)
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:将共享内存绑定到进程的地址空间里
参数:
shmid:共享内存的id
shmaddr:指定了进程绑定共享内存的地址。指定为NULL,有系统做选择
shmflg:
SHM_RDONLY:共享内存段只读
返回值:
返回和共享内存段绑定的地址
(void *) -1 错误 errno被设置
*int shmdt(const void shmaddr);
功能:解除和共享内存段的绑定
参数:
shmaddr:指定了要解除的共享内存段在进程中的地址
返回值:
0 成功
-1 失败 errno被设置
代码示例
创建共享内存段。
- shm.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int main(void){
key_t key;
//获取键值
key=ftok("hello",41);
if(key==-1){
perror("ftok");
return 1;
}
printf("key:%d\n",key);
//根据键值获取shmid
int shmid=shmget(key,1024,\
IPC_CREAT|0664);
if(shmid==-1){
perror("shmget");
return 2;
}
printf("获取到共享内存%d\n",shmid);
return 0;
}
- 执行结果
使用共享内存完成进程间通信:
- shmA.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(void){
key_t key;
//获取键值
key=ftok("hello",41);
if(key==-1){
perror("ftok");
return 1;
}
printf("key:%d\n",key);
//根据键值获取shmid
int shmid=shmget(key,1024,\
IPC_CREAT|0664);
if(shmid==-1){
perror("shmget");
return 2;
}
printf("获取到共享内存%d\n",shmid);
//将共享内存映射到进程的虚拟地址空间
void *p=shmat(shmid,NULL,0);
if(p==(void *) -1){
perror("shmat");
return 3;
}
//拷贝字符串到共享内存段
strcpy(p,"hello tarena\n");
//解除绑定
shmdt(p);
return 0;
}
- shmB.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(void){
key_t key;
//获取键值
key=ftok("hello",41);
if(key==-1){
perror("ftok");
return 1;
}
printf("key:%d\n",key);
//根据键值获取shmid
int shmid=shmget(key,1024,\
IPC_CREAT|0664);
if(shmid==-1){
perror("shmget");
return 2;
}
printf("获取到共享内存%d\n",shmid);
//将共享内存映射到进程的虚拟地址空间
void *p=shmat(shmid,NULL,0);
if(p==(void *) -1){
perror("shmat");
return 3;
}
//将共享内存段的内容输出到显示器
printf("%s",(char *)p);
//解除绑定
shmdt(p);
return 0;
}
- 执行结果
信号量集
具体参考代码示例
代码示例
- mycp.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void copy_file(int s,int d){
int r,w;
char buf[1024];
char *tmp;
r=read(s,buf,1024);
while(r>0){
tmp=buf;
while(1){//将读出的内容完全写入到目标文件
w=write(d,tmp,r);
r=r-w;
tmp+=w;
if(r==0)break;
}
r=read(s,buf,1024);
}
return;
}
int main(int argc,char *argv[]){
int s_fd,d_fd;
//以只读方式打开源文件
s_fd=open(argv[1],O_RDONLY);
if(s_fd==-1){
perror("open s");
return 1;
}
//以写的方式打开目标文件
d_fd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);
if(d_fd==-1){
perror("open d");
return 2;
}
copy_file(s_fd,d_fd);
close(s_fd);
close(d_fd);
return 0;
}
- 执行结果