IPC和文件IO函数的比较
文件I/O | IPC |
open | Msg_get Shm_get Sem_get |
read write | msgsnd msgrecv shmat shmdt semop |
close | msgctrl shmctrl semctrl |
打开或创建一个共享内存对象,共享内核在内核是什么样子的?
一块缓存,变类似于用户空间的数组或malloc函数分配的空间一样
所需头文件 | #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> |
函数原型 | int shmget(key_t key,int size,int shmflg); |
函数参数 | key:IPC_PRIVATE(私有的)或ftok的返回值 |
size:共享内存区大小 | |
shmflg:同open函数的权限位,也可以用8进制表示法 | |
函数返回 | 成功:共享内存段标识符——ID——文件描述符 失败:-1 |
查看IPC对象 ipcs -m(共享内存) -q(消息队列) -s(信号灯)
删除IPC对象 ipcrm -m id
返回值:共享内存段标识符 IPC的ID 号
通过程序来理解shmget函数的用法(第一个IPC_PRIVATE来获得)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
int main()
{
int shmid;
shmid=shmget(IPC_PRIVATE,128,0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
system("ipcs -m");
//system("ipcrm -m shmid");
return 0;
}
执行结果如下:
通过IPC_PRIVATE创建的宏key始终等于0.,可以实现有亲缘关系之间的通信
shmget类似文件IO中的open函数,会在内核中创建一个对象,我们称之为共享内存,而共享内存就是一个内核中的缓存,这个缓存就像是一个数组。
①key:第一个IPC_PRIVATE来获得,第二个通过ftok函数的返回值获得
②大小:
③权限
2.ftok函数:创建key的值。
char ftok(const char *path,char key);
参数:第一个参数:文件路径和文件名
第二个参数: 一个字符
返回值:正确返回一个key值,出错返回-1.
ftok函数可以实现无亲缘关系之间的通信。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
int main()
{
int shmid;
key_t key;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -2;
}
printf("creat key sucess key=%X\n",key);
shmid=shmget(key,128,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
system("ipcs -m");
//system("ipcrm -m shmid");
return 0;
}
执行结果如下:
发现key值这个时候再也不等于0
IPC_PRAVATE操作时,共享内存的key值都一样,都是0,所以使用ftok来创建key值。只要key值是一样的,用户空间的进程通信这个函数打开,则会对内核的同一个IPC对象操作。
(3)shmat函数 将共享内存映射到用户空间的地址中
能不能用read,write呢?
为了方便用户空间对共享内存的操作,使用地址映射的方式。
类似于malloc
void *shmat(int shmid,const void *shmaddr,int shmflg);
参数:第一个参数:ID号
第二个参数:映射到的地址,NULL为系统自动完成的映射;
第三个参数shmflg:SHM_RDONLY共享内存只读
默认是0,表示共享内存可读写。
返回值:成功:映射后的地址;
失败:NULL。
程序:shmat的设计
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
int main()
{
int shmid;
key_t key;
char *p;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -2;
}
printf("creat key sucess key=%X\n",key);
shmid=shmget(key,128,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
system("ipcs -m");
p=(char *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("shmat function failure\n");
return -3;
}
fgets(p,128,stdin);
//start read_share_memory
printf("share memory data:%s\n",p);
return 0;
}
执行后的结果为:
共享内存的特点:
-共享内存创建后,一直存在于内核中,直到被删除或系统关闭
-共享内存和管道不一样,读取后,内容仍在其共享内存中。
不过用完了共享内存之后,就释放
(4)shmdt:将用户空间进程里的地址映射删除。
int shmdt(const void *shmaddr);
参数:shmaddr共享内存映射后的地址
返回值:成功:0
失败:-1
shmdt函数的用法
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main()
{
int shmid;
key_t key;
char *p;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -2;
}
printf("creat key sucess key=%X\n",key);
shmid=shmget(key,128,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
system("ipcs -m");
p=(char *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("shmat function failure\n");
return -3;
}
fgets(p,128,stdin);
//start read_share_memory
printf("share memory data:%s\n",p);
printf("second share memory data:%s\n",p);
shmdt(p);
memcpy(p,"abcd",4);
return 0;
}
执行结果如下:
发生段错误,因为内存已经被释放
(5)shmctl函数:删除内核空间共享内存对象
函数原型:int shmctl(int shmid,int cmd,struct shmid_ds *buf);
函数参数:shmid:要操作的共享内存标识符
cmd:IPC_STAT(获取对象属性)——实现了命令ipcs -m
IPC_SET(设置对象属性)
IPC_RMID(删除对象) ——实现了命令ipcrm -m
buf:指定IPC_STAT/IPC_SET时用于保存/设置属性。
函数返回值:成功:0
失败:-1
ipcs -m:查看内核空间共享内存对象
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main()
{
int shmid;
key_t key;
char *p;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -2;
}
printf("creat key sucess key=%X\n",key);
shmid=shmget(key,128,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
system("ipcs -m");
p=(char *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("shmat function failure\n");
return -3;
}
fgets(p,128,stdin);
//start read_share_memory
printf("share memory data:%s\n",p);
printf("second share memory data:%s\n",p);
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
system("ipcs -m");
return 0;
}
执行结果如下:
共享内存被删除了
使用我们前面学到的知识构建ipcs -m和ipcrm -m这两个命令
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
int shmid;
if(argc<3)
{
printf("please input param\n");
return -1;
}
if(strcmp(argv[1],"-m")==0)
printf("delete share memory ");
else
return -2;
shmid=atoi(argv[2]);
printf("shmid=%d\n",shmid);
shmctl(shmid,IPC_RMID,NULL);
system("ipcs -m");
return 0;
}
执行结果如下:
父子进程之间的共享内存通信(IPC_PRIVATE)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
void myfunc(int signum)
{
return;
}
int main()
{
int shmid;
char *p;
pid_t pid;
shmid=shmget(IPC_PRIVATE,128,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
pid=fork();
if(pid>0)
{
signal(SIGUSR2,myfunc);
p=(char *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("parent process : shmat function failure\n");
return -3;
}
while(1)
{
printf("parent process start write share memory:\n");
fgets(p,128,stdin);
kill(pid,SIGUSR1);//child process read data
pause();//wait child process read
}
}
if(pid==0)//child process
{
signal(SIGUSR1,myfunc);
p=(char *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("child process : shmat function failure\n");
return -3;
}
while(1)
{
pause();//wait parent process write
//start read_share_memory
printf("share memory data:%s\n",p);
kill(getppid(),SIGUSR2);
}
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
system("ipcs -m");
return 0;
}
执行结果如下:
无亲缘关系进程之间的通信(必须使用ftok函数),server.c发送信号,client.c接收信号
server.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
struct mybuf{
int pid;
char buf[124];
};
void myfunc(int signum)
{
return;
}
int main()
{
int shmid;
struct mybuf *p;
int key;
pid_t pid;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -1;
}
printf("creat key sucess\n");
shmid=shmget(key,128,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
signal(SIGUSR1,myfunc);
p=(struct mybuf *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("parent process : shmat function failure\n");
return -3;
}
//get server pid
//read share memory
pid=p->pid;
//write client pid to share memory
p->pid=getpid();
//kill signal
kill(pid,SIGUSR2);
//client start read data from share memory
while(1)
{
pause();//wait server write data to share memory;
printf("client process receive data from share memory:%s",p->buf);//read data
kill(pid,SIGUSR2);//server may write share memory
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
system("ipcs -m");
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
struct mybuf{
int pid;
char buf[124];
};
void myfunc(int signum)
{
return;
}
int main()
{
int shmid;
struct mybuf *p;
int key;
pid_t pid;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -1;
}
printf("creat key sucess\n");
shmid=shmget(key,128,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory sucess shmid=%d\n",shmid);
signal(SIGUSR2,myfunc);
p=(struct mybuf *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("parent process : shmat function failure\n");
return -3;
}
//get client pid
p->pid=getpid();//write server pid to share memory
pause();//wait client read server pid;
pid=p->pid;
//write
while(1)
{
printf("parent process start write share memory:\n");
fgets(p->buf,128,stdin);
kill(pid,SIGUSR1);//client process read data
pause();//wait client process read
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
system("ipcs -m");
return 0;
}
执行结果如下: