第5章SystemV进程间通信12SystemVIPC基础消息队列3信号量通信机制4共享内存为了提供与其他系统的兼容性,Linux也支持三种SystemV的进程间通信机制:消息队列、信号量和共享内存,Linux对这些机制的实施大同小异。我们把信号量、消息队列和共享内存统称SystemVIPC对象。就像每个文件都有一个打开文件号一样,每个对象也都有唯一的识别号,进程可以通过系统调用传递的识别号来存取这些对象。与文件的存取一样,对这些对象的存取也要验证存取权限,SystemVIPC可以通过系统调用对对象的创建者设置这些对象的存取权限。2019/8/152ipcs命令Ipcs命令用于显示消息队列、共享内存、信号量的信息。q显示消息队列s显示信号量m显示共享内存a详细信息对每一个资源,这个命令会显示:TYPE包括信息队列(q),共享内存(m),或者信号量(s)。ID资源条目的唯一的表示号KEY应用程序存取资源使用的参数。MODE存取模式和许可权限的标记OWNERandGROUP登录名和用户属主的组号2019/8/153key值和ID值Linux系统为每个IPC机制都分配了唯一的ID,所有针对该IPC机制的操作都使用对应的ID。因此,通信的双方都需要通过某个办法来获取ID值。显然,创建者根据创建函数的返回值可获取该值,但另一个进程如何实现呢?由于Linux两个进程不能随意访问对方的空间(一个特殊是,子进程可以继承父亲进程的数据,实现父亲进程向子进程的单向传递),也就不能够直接获取这一ID值。为解决这一问题,IPC在实现时约定使用key值做为参数创建,如果在创建时使用相同的key值将得到同一个IPC对象的ID(即一方创建,另一方获取的是ID),这样就保证了双方可以获取用于传递数据的IPC机制ID值。2019/8/154ftokexternkey_tftok(__constchar*__pathname,int__proj_id);此函数有两个参数,pathname为文件路径名,可以是特殊文件(例如目录文件),也可以是当前目录“.”,而通常也是设置此参数为当前目录,因为当前目录一般都是存在的,且不会被立即删除。第二个参数为一个int型变量。2019/8/155例:ftok的使用#includestdio.h#includesys/types.hmain(){key_tkey;key=ftok(.,1);printf(thekeyis%x\n,key);}2019/8/15人民邮电出版社出版杨宗德编著6ftokftok函数创建key值过程中使用了该文件属性的st_dev和st_ino。具体构成如下:key值的第31-24为ftok()第二个参数的低8位;key值的第23-16为该文件的st_dev属性的低8位;key值的第15-0为该文件的st_ino属性的低16位;因此,如果使用相同的文件路径及整数,得到的key值是唯一的,而唯一的key值创建某类IPC机制时将得到同一个IPC机制(但如果使用相同的key值分别创建一个消息队列和一个信号量,两者没有联系),而文件路径的访问对两个进程来说很容易统一,因此,便捷的实现了两进程通信机制的确定。2019/8/157例:ftok函数和参数的关系#includesys/ipc.h#includestdio.h#includestdlib.h#includesys/stat.hmain(intargc,char*argv[]){key_tkey;inti;structstatbuf;if(argc!=3){printf(errorusage\n);return1;}i=atoi(argv[2]);2019/8/158例:ftok函数和参数的关系if((stat(argv[1],&buf))==-1){perror(stat);exit(EXIT_FAILURE);}printf(filest_dev=%x\n,buf.st_dev);printf(filest_ino=%x\n,buf.st_ino);printf(number=%x\n,i);key=ftok(argv[1],i);printf(key=0x%x,key);}2019/8/159第5章SystemV进程间通信12SystemVIPC基础消息队列3信号量通信机制4共享内存消息队列的基本概念消息队列就是一个消息的链表,是一系列保存在内核中的消息的列表。用户进程可以向消息队列添加消息,也可以从消息队列读取消息。消息队列与管道通信相比,其优势是对每一个消息指定特定消息类型,接收的时候不需要按队列次序,而是可以根据自定义条件接收特定类型的消息。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读取消息。2019/8/1511消息队列属性2019/8/1512消息structmsg结构体//comefrom/usr/src/kernels/’uname–r’/inlcude/linux/msg.h/*onemsg_msgstructureforeachmessage*/structmsg_msg{structlist_headm_list;longm_type;intm_ts;/*messagetestsize*/structmsg_msgseg*next;void*security;/*theactualmessagefollowsimmediately*/};2019/8/1513消息队列msg_perm权限msg_firstmsg_last...其他信息msqid_ds结构消息类型下一消息消息位置消息大小msg消息类型下一消息消息位置消息大小msg消息类型下一消息消息位置消息大小msg消息类型下一消息消息位置消息大小msg…….消息消息消息消息2019/8/1514对消息队列的说明对消息队列的限定://comefrom/usr/include/linux/msg.h#defineMSGMNI16/*=IPCMNI*//*max#ofmsgqueueidentifiers*/#defineMSGMAX8192/*=INT_MAX*//*maxsizeofmessage(bytes)*/#defineMSGMNB16384/*=INT_MAX*//*defaultmaxsizeofamessagequeue*/不同的系统限制值可以通过msgctl函数使用IPC_INFO参数获得。2019/8/1515消息队列常用的系统调用函数功能ftok根据文件路径和参数生成标准keymsgget创建或打开消息队列msgsnd添加消息msgrcv读取消息msgctl控制消息队列2019/8/1516创建消息队列externintmsgget(key_t__key,int__msgflg);第一个参数key为由ftok创建的key值。第二个参数__msgflg的低位用来确定消息队列的访问权限。如0770,为文件的访问权限类型。此外,还可以附加以下参数值。这些值可以与基本权限以或的方式一起使用。//comefrom/usr/include/bit/ipc.h/*resourcegetrequestflags*/#defineIPC_CREAT00001000/*createifkeyisnonexistent*/#defineIPC_EXCL00002000/*failifkeyexists*/#defineIPC_NOWAIT00004000/returnerroronwait*/2019/8/1517msgget返回说明:成功执行时,返回消息队列标识值。失败返回-1,errno被设为以下的某个值,有时也会返回0,这个时候也是可以正常使用的。EACCES:指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER权限EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志ENOENT:key指定的消息队列不存在,同时msgflg中不指定IPC_CREAT标志ENOMEM:需要建立消息队列,但内存不足ENOSPC:需要建立消息队列,但已达到系统的最大消息队列容量2019/8/1518例:创建消息队列#includestdio.h#includesys/ipc.h#includesys/types.hintmain(){key_tkey;key=ftok(.,1);printf(thekeyis%x\n,key);intid;id=msgget(key+1,IPC_CREAT|0666);printf(id=%d\n,id);system(“ipcs”);}2019/8/15人民邮电出版社出版杨宗德编著19消息队列属性控制externintmsgctl(int__msqid,int__cmd,structmsqid_ds*__buf);第一个参数__msqid为消息队列标识符,该值为使用msgget函数创建消息队列的返回值。第二个参数__cmd为执行的控制命令,即要执行的操作。包括以下选项://comefrom/usr/include/linux/ipc.h/*Controlcommandsusedwithsemctl,msgctlandshmctlseealsospecificcommandsinsem.h,msg.handshm.h*/#defineIPC_RMID0/*removeresource*/#defineIPC_SET1/*setipc_permoptions*/#defineIPC_STAT2/*getipc_permoptions*/#defineIPC_INFO3/*seeipcs*/2019/8/1520例:删除消息队列#includestdio.h#includesys/ipc.h#includesys/types.hintmain(){key_tkey;intid;key=ftok(.,1);id=msgget(key+1,IPC_CREAT|0666);printf(id=%d\n,id);msgctl(id,IPC_RMID,NULL);sytem(“ipcs”);}2019/8/15人民邮电出版社出版杨宗德编著21发送信息到消息队列externintmsgsnd(int__msqid,__constvoid*__msgp,size_t__msgsz,int__msgflg)第一个参数msqid为指定的消息队列标识符(由msgget生成的消息队列标识符),即将消息添加到那个消息队列中。第二个参数msgp为指向的用户定义缓冲区。第三个参数为接收信息的大小,其数据类型为size_t,即unsignedint类型。其大小为0到系统对消息队列的限定值。第四个参数用来指定在达到系统为消息队列锁定的界限(如达到字数限制)时应采取的操作。2019/8/1522发送信息到消息队列(2)第二个参数其定义如下://comefrom/usr/include/linux/msg.h/*messagebufferformsgsndandmsgrevcalls*/structmsgbuf{longmtype;/*typeofmessage*/charmtext[1];/*messagetext*/}mtype是一个正整数,由产生消息的进程生成,用于表示消息的类型,因此,接收进程可以用来进行消息选择(消息队列在存储信息时是按发送的先后顺序放置的)。mtext是文本内容,即消息内容,此处大小为1,显然不够用,在使用时自己重新定义此结构。2019/8/1523发送信息到消息队列(3)第四个参数用来指定在达到系统为消息队列锁定的界限(如达到字数限制)时应采取的操作。:如果设置为IPC_NO