IPC通信------IPC对象:1,共享内存,2,消息队列3,信号灯。
IPC对象
1,共享内存
例子1,利用shmget()函数创建共享内存;
建立shmid.c文件,内容如下
#include"system/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
int shmid;
//create shared memory
shmid=shmget(IPC_PRIVATE,128,0777);
if(shmid<0)
{
printf("create shared memory failure\n");
return -1;
}
printf("reate shared memory success\n");
system("ipc -m");//查看共享的系统内存
//system("ipc -m shmid");//删除共享内存
return 0;
}
运行编译:gcc -o shimd shmid.c
生成执行文件shmid,再运行./shimd,r如下图成功创建shmid为1802250,权限为777,大小为128的共享内存;
再运行命令:ipcrm -m 1802250就可以释放该内存,如下图。
【注】shmget()通过IPC_PRIVATE宏所创建的key,全为0,实现的是亲缘进程间的通信;
因此可采用ftork(函数)创建key值;
例子2:ftork()创建key值,建立文件ftok.c和cp.c(任意创建的文件)。ftok.c内容如下:
#include"system/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
int shmid;
int key;
key=ftork("./p.c",'p');
if(key<0)
{
printf("create key failure\n");
return -2;
}
printf("create key sucess key=%x\n",key);
//create shared memory
shmid=shmget(key,128,IPC_CREAT | 0777);//以ftork()创建的key作为要创建的共享内存的key
if(shmid<0)
{
printf("create shared memory failure\n");
return -1;
}
printf("reate shared memory success\n");
system("ipc -m");//查看共享的系统内存
//system("ipc -m shmid");//删除共享内存
return 0;
}
编译运行:./ftok
可以通过修改ftok()函数的第二参数值来创建不同的key值,ftok实现非亲缘关系进程之间的通信。
由于shmget()函数所创建的共享内存在内核空间,进程间同过共享内存通信,每次都要调用write(),read()等系统函数,非常麻烦。所有引入shmat函数,该函数可以将内核的共享内存印射到用户空间,从而实现两个进程之间通信时可以不用每次通信都经过内核。
例子3:shmat的用法,建立shmat.c文件,内容如下:
#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
int shmid;
int key;
char *p;
key=ftok("./p.c",'p');
if(key<0)
{
printf("create key failure\n");
return -2;
}
printf("create key sucess key=%x\n",key);
//create shared memory
shmid=shmget(key,128,IPC_CREAT | 0777);//以ftork()创建的key作为要创建的共享内存的key
if(shmid<0)
{
printf("create shared memory failure\n");
return -1;
}
printf("reate shared memory success\n");
p=(char*)shmat(shmid,NULL,0);//印射创建的共享内存到内核用户空间
if(p==NULL)
{
printf("shmat function failure\n");
return -3;
}
//write something to share memory
fgets(p,128,stdin);//从标准输入写入共享内存
//read to stdout
printf("first shared memory =");//第一次读取
fputs(p,stdout);
printf("\nsecond shared memory =");//第二次读取共享内存的内容
fputs(p,stdout);//从共享内存读出到标准输出
system("ipcs -m");//查看共享的系统内存
return 0;
}
运行结果:
共享内存可以多次读取,里面的信息不会被删除。
例子4:将共享内存空间印射到用户空间的地址删除;shmdt()函数的应用。建立shmdt.c文件,内容基于例子3,添加两行代码,
shmdt(p);//释放用户空间印射的地址
mecpy(p,"hello",5);//释放后再向该地址写东西时,会发生段错误。
如下;
#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
int shmid;
int key;
char *p;
key=ftok("./p.c",'p');
if(key<0)
{
printf("create key failure\n");
return -2;
}
printf("create key sucess key=%x\n",key);
//create shared memory
shmid=shmget(key,128,IPC_CREAT | 0777);//以ftork()创建的key作为要创建的共享内存的key
if(shmid<0)
{
printf("create shared memory failure\n");
return -1;
}
printf("reate shared memory success\n");
p=(char*)shmat(shmid,NULL,0);//印射创建的共享内存到内核用户空间
if(p==NULL)
{
printf("shmat function failure\n");
return -3;
}
//write something to share memory
fgets(p,128,stdin);//从标准输入写入共享内存
//read to stdout
printf("first shared memory =");//第一次读取
fputs(p,stdout);
printf("\nsecond shared memory =");//第二次读取共享内存的内容
fputs(p,stdout);//从共享内存读出到标准输出
system("ipcs -m");//查看共享的系统内存
shmdt(p);//释放用户空间印射的地址
mecpy(p,"hello",5);//释放后再向该地址写东西时,会发生段错误。
return 0;
}
运行结果如下:
shmctl()函数分析:
75c645b5e0904621407f0a5827dd7f33.png
如图上,用户印射地址被释放。接下来再用shmctl()函数释放内核的共享内存地址,基于例4,再return 0;前加入
shmctl(shmid,IPC_RMID,NULL);//free kernel shared memory
system("ipcs -m");//释放内核共享内存后,查看共享内存是否还在
结果是:共享内存分配后,调用shmctl()函数将其又释放了。
【注意】删除共享内存时,shmctl()的第二个参数为RMID,第三个参数可以设置为NULL,当第二个参数为IPC_SET,IPC_STAT时,第三个参数才要设置。
例子5:利用shmctl()函数实现共享内存的删除命令:ipcrm -m shmid
建立ipcrm.c,内容如下:
#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
int main(int argc,char *argv[])
{
if(argc<3)
{
printf("please input 3 param\n");
return -1;
}
if(strcmp(argv[1],"m") ==0)
{
printf("delete shared memory");
}
else
{
return -2;
}
int shmid;
shmid=atoi(argv[2]);//获取用户输入shmid
printf("shmid=%d\n",shmid);
shmctl(shmid,IPC_RMID,NULL);
system("ipcrm -m ");
return 0;
}
运行编译命令:gcc -o ipcrm ipcrm.c
生成ipcrm执行文件,此时运行:./ipcrm -m shmid 就等价于ipcrm -m shmid
父子进程之间及非亲缘进程之间的通信,具体体现ftok()函数的key,IPC_PRAVITE的区别
综合实例1:用共享内存实现主进程A和子进程B之间的通信。
建立文件parent_child_communition.c,具体代码如下:
unition.c
#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
void myfun_parent(int signum)
{
printf("parent gets signal is %d\n",signum);
return;
}
void myfun_child(int signum)
{
printf("child gets signal is %d\n",signum);
return;
}
int main()
{
pid_t pid;
int shmid;
char *p;
shmid=shmget(IPC_PRIVATE,128,0777);//create shared memory
if(shmid<0)
{
printf("create shared memory failure\n");
return -1;
}
printf("create shared memory success\n");
pid=fork();
if(pid>0)//parent process code
{
signal(SIGUSR2,myfun_parent);
p=(char*)shmat(shmid,NULL,0);//reflect the shared memory to usrmemory
if(p==NULL)
{
printf("reflect the shared memory failure\n");
return -2;
}
//reserve to write data to usrmemory
while(1)
{
printf("parent process start to write data to usrmemory\n");
fgets(p,128,stdin);//get data from stdin
kill(pid,SIGUSR1);//send to tell child process after data writed
pause();//wait to child proces read
}
}
if(pid==0)//child proces code
{
signal(SIGUSR1,myfun_child);//receive signal from parent process and jumb to myfun
p=(char*)shmat(shmid,NULL,0);//relect shared memory to own
if(p==NULL)
{
printf("reflect shared memory to child process failure\n");
return -3;
}
while(1)
{
pause();//wait parent process write
//start to read the shared memory
printf("here is child,the data writed into shared memory are:%s\n",p);
fputs(p,stdout);//read to standard output
kill(getppid(),SIGUSR2);//then send SIGUSR2 to tell parent process
}
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
【注意】shmget()函数要在fork()函数之前,否则父子进程会分别创建出自己不同的共享内存,这样就无法进行通信了,因为父子进程通信要对同一个共享内存进行读写。
综合实例2:非亲缘进程之间的通信,菜用fork函数生成共享内存的非零key值。
建立server.c,client.c,f.c(无内容要求)文件
server.c代码如下:
#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
typedef struct buf{
int pid;
char shm_buf[124];
}BUF;
void myfun_A(int signum)
{
printf("server gets signal is %d\n",signum);
return;
}
int main()
{
pid_t pid;
int shmid;
BUF *p;
int key;
key=ftok("./f.c",'f');
if(key<0)
{
printf("create shmid's key failure\n");
return -3;
}
printf("create shmid's key success, key =%d\n",key);
shmid=shmget(key,128,IPC_CREAT | 0777);//create shared memory
if(shmid<0)
{
printf("create shared memory failure\n");
return -1;
}
printf("create shared memory success\n");
signal(SIGUSR2,myfun_A);
p=(BUF*)shmat(shmid,NULL,0);//reflect the shared memory to usrmemory
if(p==NULL)
{
printf("reflect the shared memory failure\n");
return -2;
}
p->pid=getpid();//write A process pid to share memory
pause();//wait B process read A process pid
pid=p->pid;//read B process pid from shared memory
//A process to write data to usrmemory
while(1)
{
printf("read the shared memory data writed by B process\n");
fputs(p->shm_buf,stdout);//read to standard output
if(strcmp(p->shm_buf,"shutdown\0")==0)break;
printf("A process start to write data to usrmemory\n");
fgets(p->shm_buf,128,stdin);//get data from stdin
kill(p->pid,SIGUSR1);//send signal to tell B process after data writed
pause();//wait B process read
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
system("ipcs -m");
return 0;
}
client.c代码如下:
#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
typedef struct buf{
int pid;
char shm_buf[124];
}BUF;
void myfun_B(int signum)
{
printf("B process gets signal is %d\n",signum);
return;
}
int main()
{
pid_t pid;
int shmid;
BUF *p;
int key;
key=ftok("./f.c",'f');
if(key<0)
{
printf("create shmid's key failure\n");
return -3;
}
printf("create shmid's key success, key=%d\n",key);
shmid=shmget(key,128,IPC_CREAT | 0777);//create shared memory
if(shmid<0)
{
printf("create shared memory failure\n");
return -1;
}
printf("create shared memory success\n");
signal(SIGUSR1,myfun_B);
p=(BUF*)shmat(shmid,NULL,0);//reflect the shared memory to usrmemory
if(p==NULL)
{
printf("reflect the shared memory failure\n");
return -2;
}
//get A process pid
pid=p->pid;
//write B process pid to shared memory
p->pid=getpid();
//send signal to A
kill(pid,SIGUSR2);
//B process start to read data from usrmemory
while(1)
{
pause();//wait A process to write data to shared memory
printf("B process start to read data from usrmemory\n");
fputs(p->shm_buf,stdout);//get data from stdin
printf("write something to shared memory\n");
fgets(p->shm_buf,128,stdin);//write to something to shared memory
kill(pid,SIGUSR2);//send to tell B process after data writed
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
system("ipcs -m");
return 0;
}
以上是进程间通过共享内存的通信总结。