IPC(Inter-Process Communication,进程间通信)
system V posix 提供的一套操作系统的接口标准 , linux、Unix都是纯C代码写的 , 有了这个标准 , 移植会很方便
原理及实现:system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去。这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信。共享内存允许一个或多个进程通过同时出现在它们的虚拟地址空间的内存进行通信,而这块虚拟内存的页面被每个共享进程的页表条目所引用,同时并不需要在所有进程的虚拟内存都有相同的地址。进程对象对于共享内存的访问通过key(键)来控制,同时通过key进行访问权限的检查。 |
同一份物理内存被映射到多个进程地址空间
ipcs 查看共享内存 ipcrm -m shmid 删除共享内存
函数定义如下: #include <sys/ipc.h>
#include <sys/shm.h>
key_t ftok(const char *pathname, int proj_id); //生成关联共享内存段的关键字, proj_id只要不是0就行;传一个文件不是要拿来写东西,而是和后面的整形参数结合生成一个关键字key
int shmget(key_t key, int size, int shmflg); //第一个进程创建共享内存,后面进程调用就是获取该内存(返回共享内存id(shmid))
//共享内存开辟的空间物理上是不连续的,但是映射到进程地址空间是连续的,因为只有这样才能操作这段共享内存。
void *shmat(int shmid, const void *shmaddr, int shmflg); //链接,后面两个参数通常为NULL,0,默认由系统将对应共享内存映射到当前进程的虚拟地址空间,0是因为前面创建或获取已经设置了权限,所以这里直接填0就可以了
int shmdt(const void *shmaddr); //解除链接
int shmctl(int shmid, int cmd, struct shmid_ds *buf); //控制函数,可以用来删除共享内存段
|
函数ftok 用于创建一个关键字,可以用该关键字关联一个共享内存段。
参数pathname为一个全路径文件名,并且该文件必须可访问。
参数proj_id通常传入一非0字符
通过pathname和proj_id组合可以创建唯一的key
如果调用成功,返回一关键字,否则返回-1
|
函数shmget 用于创建或打开一共享内存段,该内存段由函数的第一个参数唯一创建。函数成功,则返回一个唯一的共享内存标识号(相当于进程号,唯一的标识着共享内存),失败返回-1。
参数key是一个与共享内存段相关联关键字,如果事先已经存在一个与指定关键字关联的共享内存段,则直接返回该内存段的标识,表示打开,如果不存在,则创建一个新的共享内存段。key的值既可以用ftok函数产生,也可以是IPC_PRIVATE(用于创建一个只属于创建进程的共享内存,主要用于父子通信),表示总是创建新的共享内存段;
参数size指定共享内存段的大小,以字节为单位;
参数shmflg是一掩码合成值,可以是访问权限值与(IPC_CREAT或IPC_EXCL)的合成。IPC_CREAT表示如果不存在该内存段,则创建它。IPC_EXCL表示如果该内存段存在,则函数返回失败结果(-1)。如果调用成功,返回内存段标识,否则返回-1。
|
函数shmat 将共享内存段映射到进程空间的某一地址。
参数shmid是共享内存段的标识,通常应该是shmget的成功返回值。
参数shmaddr指定的是共享内存连接到当前进程中的地址位置。通常是NULL,表示让系统来选择共享内存出现的地址。
参数shmflg是一组位标识,通常为0即可。
如果调用成功,返回映射后的进程空间的首地址,否则返回(char *)-1。
|
函数shmdt 用于将共享内存段与进程空间分离。
参数shmaddr通常为shmat的成功返回值。
函数成功返回0,失败时返回-1.注意,将共享内存分离并没删除它,只是使得该共享内存对当前进程不在可用。
|
函数shmctl是共享内存的控制函数,可以用来删除共享内存段。
参数shmid是共享内存段标识,通常应该是shmget的成功返回值
参数cmd是对共享内存段的操作方式,可选为IPC_STAT,IPC_SET,IPC_RMID。通常为IPC_RMID,表示删除共享内存段。
参数buf是表示共享内存段的信息结构体数据,通常为NULL(遇到IPC_RMID)。
有进程连接,执行返回0,删除失败。
|
shm.c | |
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#define SIZE 20
int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t key=ftok(argv[1],1); //第二个参数非0就行,第一个参数也是用来生成 key 而已
int shmid=shmget(key,SIZE,IPC_CREAT|0666);
if(-1==shmid)
{
perror("error shmid\n");
return -1;
}
return 0;
}
|
//共享内存在进程退出后不会消失,私有共享内存key都是0
非亲进程间通信的实现:
shm_w.c | shm_r.c |
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#define SIZE 20
int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t key=ftok(argv[1],1); //第二个参数非0
int shmid=shmget(key,SIZE,IPC_CREAT|0666); //创建
if(-1==shmid)
{
perror("error shmid\n");
return -1;
}
char* p;
p=(char*)shmat(shmid,NULL,0); //链接,后面两个参数默认
if((char*)-1==p)
{
perror("shmat");
return -1;
}
p[0]='H'; //写内容
sleep(10); //方便查看ipcs
int ret=shmdt(p); //解除链接
if(ret!=0)
{
perror("shmdt");
return -1;
}
return 0;
}
//共享内存往里面写入数据,写端关闭了,读端再次链接到这段内存还能把这个数据读出来
|
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#define SIZE 20
int main(int argc,char* argv[])
{
if(argc!=2)
{
printf("error args\n");
return -1;
}
key_t key=ftok(argv[1],1); //第二个参数非0
int shmid=shmget(key,SIZE,IPC_CREAT|0666); //创建
if(-1==shmid)
{
perror("error shmid\n");
return -1;
}
char* p;
p=(char*)shmat(shmid,NULL,0); //链接,后面两个参数默认
if((char*)-1==p)
{
perror("shmat");
return -1;
}
printf("%c\n",p[0]) //写内容
sleep(10); //方便查看ipcs
int ret=shmdt(p); //解除链接
if(ret!=0)
{
perror("shmdt");
return -1;
}
return 0;
}
|
2016/5/19 10:01:26
有亲缘关系
进程间通信的实现:
shmget_private.c | |
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<string.h>
#include<sys/wait.h>
#include<stdlib.h>
int main()
{
int shmid = shmget(IPC_PRIVATE,1024,IPC_CREAT|0666);
if( fork() )
{
char *p = (char*)shmat(shmid,NULL,0);
//私有共享内存,key都是0
char buf[128];
strcpy(p,"hello , world!");
sleep(10);
shmdt(p);
wait(NULL);
int ret = shmctl(shmid,IPC_RMID,NULL); //删除共享内存
if(0!=ret)
{
perror("shmctl");
exit(0);
}
}
else
{
char *p = (char*)shmat(shmid,NULL,0);
char buf[128];
strcpy(buf,p);
printf("buf=%s\n",p);
sleep(10);
shmdt(p);
exit(0);
}
return 0;
}
|
IPC_struct.c | IPC_struct_read.c |
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<string.h>
#include<sys/wait.h>
#include<stdlib.h>
typedef struct student
{
int num ;
char name[20];
}stu,*pstu;
int main()
{
int shmid = shmget((key_t)110,sizeof(stu),IPC_CREAT|0666);
pstu p = (pstu)shmat(shmid,NULL,0);
p->num = 2017;
strcpy(p->name,"meihao");
shmdt(p);
return 0;
}
|
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<string.h>
#include<sys/wait.h>
#include<stdlib.h>
typedef struct student
{
int num;
char name[20];
}stu,*pstu;
int main()
{
int shmid = shmget( (key_t)110,sizeof(stu),IPC_CREAT|0666 );
stu s;
pstu p = shmat(shmid,NULL,0);
memcpy(&s,p,sizeof(stu));
printf("read struct num=%d name=%s\n",s.num,s.name);
shmdt((void *)p);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
如果有人链接,删除不了,但是返回的是成功,key 变成 0 (私有共享内存),这个时候如果这块内存的链接全部解除,相应的这块内存就被删除了。
|
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid_ds结构体
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
|
struct ipc_perm {
key_t __key; /* Key supplied to shmget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions + SHM_DEST and
SHM_LOCKED flags */
unsigned short __seq; /* Sequence number */
};
|
shmctl_stat.c | shmctl_set.c |
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
int shmid=shmget((key_t)1234,20,IPC_CREAT|0600);
if(-1==shmid)
{
perror("shmget");
return -1;
}
struct shmid_ds buf;
int ret=shmctl(shmid,IPC_STAT,&buf);
if(-1==ret)
{
perror("shmctl");
return -1;
}
printf("cuid=%d,mode=%d,size=%ld,nattch=%ld\n",buf.shm_perm.cuid,buf.shm_perm.mode,buf.shm_segsz,buf.shm_nattch);
return 0;
}
|
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
int shmid=shmget((key_t)1234,1024,IPC_CREAT|0600);
if(-1==shmid)
{
perror("shmget");
return -1;
}
struct shmid_ds buf;
int ret=shmctl(shmid,IPC_STAT,&buf);
if(-1==ret)
{
perror("shmctl");
return -1;
}
printf("cuid=%d,mode=%d,size=%ld,nattch=%ld\n",buf.shm_perm.cuid,buf.shm_perm.mode,buf.shm_segsz,buf.shm_nattch);
buf.shm_perm.mode=0666;
ret=shmctl(shmid,IPC_SET,&buf);
printf("cuid=%d,mode=%d,size=%ld,nattch=%ld\n",buf.shm_perm.cuid,buf.shm_perm.mode,buf.shm_segsz,buf.shm_nattch);
if(-1==ret)
{
perror("shmctl2");
return -1;
}
return 0;
}
|