Unix环境高级编程008.pdf

上传人:asd****56 文档编号:70321845 上传时间:2023-01-19 格式:PDF 页数:50 大小:1.88MB
返回 下载 相关 举报
Unix环境高级编程008.pdf_第1页
第1页 / 共50页
Unix环境高级编程008.pdf_第2页
第2页 / 共50页
点击查看更多>>
资源描述

《Unix环境高级编程008.pdf》由会员分享,可在线阅读,更多相关《Unix环境高级编程008.pdf(50页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、struct sem ushort s e m v a l;/*semaphore value,always=0*/pid_t s e m p i d;/*pid for last operarion*/ushort s e m n c n t;/*#processes awaiting semval currval*/ushort s e m z c n t;/*#processes awaiting semval=0*/;表1 4-6列出了影响信号量集合的系统限制(见1 4.6.3节)。表14-6 影响信号量的系统限制要调用的第一个函数是s e m g e t以获得一个信号量I D。#in

2、clude#include#include int semget(key_t k e y,int n s e m s,int f l a g);返回:若成功则返回信号量I D,若出错则为-11 4.6.1节说明了将k e y变换为标识符的规则,讨论了是否创建一个新集合,或是引用一个现存的集合。但创建一个新集合时,对s e m i d _ d s结构的下列成员赋初值:按1 4.6.2节中所述,对i p c _ p e r m结构赋初值。该结构中的m o d e被设置为f l a g中的相应许可权位。这些许可权是用表1 4-2中的常数设置的。sem_otime设置为0。sem_ctime设置为当前

3、时间。sem_nsems设置为n s e m s。n s e m s是该集合中的信号量数。如果是创建新集合(一般在服务器中),则必须指定n s e m s。如果引用一个现存的集合(一个客户机),则将n s e m s指定为0。s e m c t l函数包含了多种信号量操作。#include#include#include int semctl(int s e m i d,int s e m n u m,int c m d,union semun a rg);返回:(见下)第1 4章进程间通信3 4 3下载名字说明典型值S E M V M X任一信号量的最大值32 767S E M A E M任

4、一信号量的最大终止时调整值16 384S E M M N I系统中信号量集的最大数1 0S E M M N S系统中信号量集的最大数6 0S E M M S L每个信号量集中的最大信号量数2 5S E M M N U系统中u n d o结构的最大数3 0S E M U M E每个u n d o结构中的最大u n d o项数1 0S E M O P M每个s e m o p调用所包含的最大操作数1 0注意,最后一个参数是个联合(u n i o n),而非指向一个联合的指针。union semun int v a l;/*for SETVAL*/struct semid_ds*b u f;/*fo

5、r IPC_STAT and IPC_SET*/u s h o r t*a r r a y;/*for GETALL and SETALL*/;c m d参数指定下列十种命令中的一种,使其在s e m i d指定的信号量集合上执行此命令。其中有五条命令是针对一个特定的信号量值的,它们用 s e m n u m指定该集合中的一个成员。s e m n u m值在0和n s e m s1之间(包括0和n s e m s1)。IPC_STAT 对此集合取s e m i d _ d s结构,并存放在由a rg.b u f指向的结构中。IPC_SET 按由a rg.b u f指向的结构中的值设置与此集合相

6、关结构中的下列三个字段值:s e m _ p e r m.u i d,s e m _ p e r m.g i d和s e m _ p e r m.m o d e。此命令只能由下列两种进程执行:一种是其有效用户I D等于s e m _ p e r m.c u i d或s e m _ p e r m.u i d的进程;另一种是具有超级用户特权的进程。IPC_RMID 从系统中删除该信号量集合。这种删除是立即的。仍在使用此信号量的其他进程在它们下次意图对此信号量进行操作时,将出错返回 E I D R M。此命令只能由下列两种进程执行:一种是具有效用户I D等于s e m _ p e r m.c u

7、i d或s e m _ p e r m.u i d的进程;另一种是具有超级用户特权的进程。GETVAL 返回成员s e m n u m的s e m v a l值。SETVAL 设置成员s e m n u m的s e m v a l值。该值由a rg.v a l指定。GETPID 返回成员s e m n u m的s e m p i d值。GETNCNT 返回成员s e m n u m的s e m n c n t值。GETZCNT 返回成员s e m n u m的s e m z c n t值。GETALL 取该集合中所有信号量的值,并将它们存放在由a rg.a rr a y指向的数组中。SETAL

8、L 按a rg.a rr a y指向的数组中的值设置该集合中所有信号量的值。对于除G E TA L L以外的所有G E T命令,s e m c t l函数都返回相应值。其他命令的返回值为 0。函数s e m o p自动执行信号量集合上的操作数组。#include#i n c l u d e#i n c l u d eint semop(int s e m i d,struct sembuf s e m o p a rr a y,size_t n o p s);返回:若成功则为0,若出错则为-1s e m o p a rr a y是一个指针,它指向一个信号量操作数组。struct sembuf

9、u s h o r ts e m _ n u m;/*member#in set(0,1,nsems-1*/s h o r ts e m _ o p;/*operation(negative,0,or pasitive*/)s h o r ts e m _ f l g;/*IPC_NOWAIT,SEM_UNDO*/;n o p s规定该数组中操作的数量(元素数)。对集合中每个成员的操作由相应的s e m _ o p规定。此值可以是负值、0或正值。(下面的讨论将提到信号量的u n d o标志。此标志对应于相应s e m _ f l g成员的S E M _ U N D O位。)(1)最易于处理的情

10、况是s e m _ o p为正。这对应于返回进程占用的资源。s e m _ o p值加到信号3 4 4U N I X环境高级编程下载量的值上。如果指定了u n d o标志,则也从该进程的此信号量调整值中减去s e m _ o p。(2)若s e m _ o p为负,则表示要获取由该信号量控制的资源。如若该信号量的值大于或等于 s e m _ o p的绝对值(具有所需的资源),则从信号量值中减去s e m _ o p的绝对值。这保证信号量的结果值大于或等于 0。如果指定了u n d o标志,则s e m _ o p的绝对值也加到该进程的此信号量调整值上。如果信号量值小于s e m _ o p的绝

11、对值(资源不能满足要求),则:(a)若指定了I P C _ N O WA I T,则出错返回E A G A I N;(b)若未指定I P C _ N O WA I T,则该信号量的s e m n c n t值加1(因为将进入睡眠状态),然后调用进程被挂起直至下列事件之一发生:i.此信号量变成大于或等于s e m _ o p的绝对值(即某个进程已释放了某些资源)。此信号量的s e m n c n t值减1(因为已结束等待),并且从信号量值中减去s e m _ o p的绝对值。如果指定了u n d o标志,则s e m _ o p的绝对值也加到该进程的此信号量调整值上。ii.从系统中删除了此信号量

12、。在此情况下,函数出错返回E R M I D。iii.进程捕捉到一个信号,并从信号处理程序返回,在此情况下,此信号量的 s e m n c n t值减1(因为不再等待),并且函数出错返回E I N T R.(3)若s e m _ o p为0,这表示希望等待到该信号量值变成0。如果信号量值当前是0,则此函数立即返回。如果信号量值非0,则:(a)若指定了I P C _ N O WA I T,则出错返回E A G A I N;(b)若未指定I P C _ N O WA I T,则该信号量的s e m n c n t值加1(因为将进入睡眠状态),然后调用进程被挂起,直至下列事件之一发生:i.此信号量值

13、变成0。此信号量的s e m z c n t值减1(因为已结束等待)。ii.从系统中删除了此信号量。在此情况下,函数出错返回E R M I D。iii.进程捕捉到一个信号,并从信号处理程序返回。在此情况下,此信号量的 s e m z c n t值减1(因为不再等待),并且函数出错返回E I N T R.s e m o p具有原子性,因为它或者执行数组中的所有操作,或者一个也不做。e x i t时的信号量调整正如前面提到的,如果在进程终止时,它占用了经由信号量分配的资源,那么就会成为一个问题。无论何时只要为信号量操作指定了S E M _ U N D O标志,然后分配资源(s e m _ o p值

14、小于0),那么内核就会记住对于该特定信号量,分配给我们多少资源(s e m _ o p的绝对值)。当该进程终止时,不论自愿或者不自愿,内核都将检验该进程是否还有尚未处理的信号量调整值,如果有,则按调整值对相应量值进行调整。如果用带S E T VA L或S E TA L L命令的s e m c t l设置一信号量的值,则在所有进程中,对于该信号量的调整值都设置为0。实例信号量与记录锁的时间比较如果多个进程共享一个资源,则可使用信号量或记录锁。对这两种技术在时间上的差别进行比较是有益的。若使用信号量,则先创建一个包含一个成员的信号量集合,然后对该信号量值赋初值1。为了分配资源,以s e m _ o

15、 p为1调用s e m o p,为了释放资源,则以 s e m _ o p为+1调用s e m o p。对每个操作都指定S E M _ U N D O,以处理在未释放资源情况下进程终止的情况。第1 4章进程间通信3 4 5下载若使用记录锁,则先创建一个空文件,并且用该文件的第一个字节(无需存在)作为锁字节。为了分配资源,先对该字节获得一个写锁,释放该资源时,则对该字节解锁。记录锁的性质确保了,当有一个锁的进程终止时,内核会自动释放该锁。表1 4-7显示了在两个不同系统上,使用这两种不同技术进行锁操作所需的时间。在各种情况中,资源都被分配,然后释放10 000次。这同时由三个不同的进程执行。表

16、1 4-7中所示的时间是三个进程的总计,单位是秒。表14-7 信号量锁和记录锁的时间比较在S PA R C上,记录锁与信号量锁相比,在系统时间方面要多耗用 1 0%。在8 0 3 8 6上,多耗用约5 0%。虽然记录锁稍慢于信号量锁,但如果只需锁一个资源(例如共享存储段)并且不需要使用系统V信号量的所有花哨的功能,则宁可使用记录锁。理由是:(a)使用简易,(b)进程终止时,会处理任一遗留下的锁。14.9 共享存储共享存储允许两个或多个进程共享一给定的存储区。因为数据不需要在客户机和服务器之间复制,所以这是最快的一种 I P C。使用共享存储的唯一窍门是多个进程之间对一给定存储区的同步存取。若服

17、务器将数据放入共享存储区,则在服务器做完这一操作之前,客户机不应当去取这些数据。通常,信号量被用来实现对共享存储存取的同步。(不过正如前节最后部分所述,记录锁也可用于这种场合。)内核为每个共享存储段设置了一个s h m i d _ d s结构。表1 4-8列出了影响共享存储的系统限制(见1 4.6.3节)。调用的第一个函数通常是s h m g e t,它获得一个共享存储标识符。#include#include 3 4 6U N I X环境高级编程下载操作S PARC,SunOS 4.1.18 0 3 8 6,S V R 4用户系统时钟用户系统时钟带u n d o的信号量0.91 3.91 5.

18、00.51 3.11 3.7建议性纪录锁1.11 5.21 6.52.12 0.62 2.9#include int shmget(key_t k e y,int s i z e,int f l a g);返回:若成功则为共享内存I D,若出错则为-1表14-8 影响共享存储的系统限制1 4.6.1节说明了将k e y变换成一个标识符的规则,以及是创建一个新共享存储段或是存访一个现存的共享存储段。当创建一个新段时,初始化s h m i d _ d s结构的下列成员:ipc_perm结构按1 4.6.2节中所述进行初始化。该结构中的m o d e按f l a g中的相应许可权位设置。这些许可权用

19、表1 4-2中的常数指定。shm_lpid、s h m _ n a t t a c h、s h m _ a t i m e、以及s h m _ d t i m e都设置为0。shm_ctime设置为当前时间。s i z e是该共享存储段的最小值。如果正在创建一个新段(一般在服务器中),则必须指定其s i z e。如果正在存访一个现存的段(一个客户机),则将s i z e指定为0。s h m c t l函数对共享存储段执行多种操作。#include#include#include int shmctl(int s h m i d,int c m d,struct shmid_ds *b u f)

20、;返回:若成功则为0,若出错则为-1c m d参数指定下列5种命令中一种,使其在s h m i d指定的段上执行。IPC_STAT 对此段取s h m i d _ d s结构,并存放在由b u f指向的结构中。IPC_SET 按 b u f指向的结构中的值设置与此段相关结构中的下列三个字段:s h m _ p e r m.u i d、s h m _ p e r m.g i d以及s h m _ p e r m.m o d e。此命令只能由下列两种进程执行:一种是其有效用户I D等于s h m _ p e r m.c u i d或s h m _ p e r m.u i d的进程;另一种是具有超级

21、用户特权的进程。IPC_RMID 从系统中删除该共享存储段。因为每个共享存储段有一个连接计数(s h m _ n a t t c h在s h m i d _ d s结构中),所以除非使用该段的最后一个进程终止或与该段脱接,否则不会实际上删除该存储段。不管此段是否仍在使用,该段标识符立即被删除,所以不能再用s h m a t与该段连接。此命令只能由下列两种进程执行:一种是其有效用户I D等于s h m _ p e r m.c u i d或s h m _ p e r m.u i d的进程;另一种是具有超级用户特权的进程。SHM_LOCK 锁住共享存储段。此命令只能由超级用户执行。SHM_UNLOC

22、K 解锁共享存储段。此命令只能由超级用户执行。一旦创建了一个共享存储段,进程就可调用s h m a t将其连接到它的地址空间中。第1 4章进程间通信3 4 7下载名字说明典型值S H M M A X共享存储段的最大字节数131 072S H M M I N共享存储段的最小字节数1S H M M N I系统中共享存储段的最大段数1 0 0S H M S E G每个进程,共享存储段的最大段数6#include#include#include void*shmat(int s h m i d,void*a d d r,int f l a g);返回:若成功则为指向共享存储段的指针,若出错则为-1共享

23、存储段连接到调用进程的哪个地址上与 a d d r参数以及在f l a g中是否指定S H M _ R N D位有关。(1)如果a d d r为0,则此段连接到由内核选择的第一个可用地址上。(2)如果a d d r非0,并且没有指定S H M _ R N D,则此段连接到a d d r所指定的地址上。(3)如果a d d r非0,并且指定了S H M _ R N D,则此段连接到(a d d r(a d d r mod SHMLBA))所表示的地址上。S H M _ R N D命令的意思是:取整。S H M L B A的意思是:低边界地址倍数,它总是2的乘方。该算式是将地址向下取最近1个S H

24、 M L B A的倍数。除非只计划在一种硬件上运行应用程序(这在当今是不大可能的),否则不用指定共享段所连接到的地址。所以一般应指定a d d r为0,以便由内核选择地址。如果在f l a g中指定了S H M _ R D O N LY位,则以只读方式连接此段。否则以读写方式连接此段。s h m a t的返回值是该段所连接的实际地址,如果出错则返回 1。当对共享存储段的操作已经结束时,则调用 s h m d t脱接该段。注意,这并不从系统中删除其标识符以及其数据结构。该标识符仍然存在,直至某个进程(一般是服务器)调用s h m c t l(带命令I P C _ R M I D)特地删除它。#i

25、nclude#include#include int shmdt(void *a d d r);返回:若成功则为0,若出错则为-1a d d r参数是以前调用s h m a t时的返回值。实例内核将以地址0连接的共享存储段放在什么位置上与系统密切相关。程序 1 4-11打印一些信息,它们与指定系统将不同类型的数据放在什么位置有关。在一个特定的系统上运行此程序,其输出如下:$a.o u tarray from 18f48 to 22b88stack around f7fffb2cmalloced from 24c28 to 3d2c8shared memory attached from f77

26、d0000 to f77e86a0图1 4-1 3显示了这种情况,这与图7-3中所示的典型存储区布局类似。注意,共享存储段紧靠在栈之下。实际上,在共享存储段和栈之间有大约8 M字节的未用地址空间。3 4 8U N I X环境高级编程下载程序1 4-11 打印不同类型的数据所存放的位置实例/d e v/z e r o的存储映射共享存储可由不相关的进程使用。但是,如果进程是相关的,则 S V R 4提供了一种不同的第1 4章进程间通信3 4 9下载图14-13 特定系统上的存储区布局命令行参数和环境变量共享存储,100 000字节malloc,100 000字节array,40 000字节栈共享存

27、储堆非初始化数据(b s s)初始化数据正文低地址高地址技术。设备/d e v/z e r o在读时,是0字节的无限资源。此设备也接收写向它的任何数据,但忽略此数据。我们对此设备作为I P C的兴趣在于,当对其进行存储映射时,它具有一些特殊性质:创建一个未名存储区,其长度是m m a p的第二个参数,将其取整为系统上的最近页长。存储区都初始化为0。如果多个进程的共同祖先进程对m m a p指定了M A P _ S H A R E D标志,则这些进程可共享此存储区。程序1 4-1 2是使用此特殊设备的一个例子。它打开此/d e v/z e r o设备,然后指定一个长整型调用m m a p。注意,

28、一旦该存储区被映射了,就能关闭此设备。然后,进程创建一个子进程。因为在调用m m a p时指定了M A P _ S H A R E D,所以一个进程写到存储映照区的数据可由另一进程见到。(如果已指定M A P _ P R I VAT E,则此程序不会工作。)然后,父、子进程交替运行,使用 8.8节中的同步函数各自对共享存储映射区中的一个长整型数加1。存储映射区由m m a p初始化为0。父进程先对它进行增1操作,使其成为1,然后子进程对其进行增1操作,使其成为2,然后父进程使其成为 3注意,当在u p d a t e函数中,对长整型值增1时,必须使用括号,因为增加的是其值,而不是指针。程序14

29、-12 在父、子进程间使用/d e v/z e r o存储映射I/O的I P C3 5 0U N I X环境高级编程下载以上述方式使用/d e v/z e r o的优点是:在调用m m a p创建映射区之前,无需存在一个实际文件。映射/d e v/z e r o自动创建一个指定长度的映射区。这种技术的缺点是:它只能由相关进程使用。如果在无关进程之间需要使用共享存储区,则必须使用 s h m X X X函数。实例匿名存储映射4.3+B S D提供了一种类似于/d e v/z e r o的施设,称为匿名存储映射。为了使用这种功能,在调用m m a p时指定M A P _ A N O N标志,并将描

30、述符指定为1。结果得到的区域是匿名的(因为它并不通过一个文件描述符与一个路径名相结合),并且创建一个存储区,它可与后代进程共享。为了使程序1 4-1 2应用4.3+B S D的这种特征,做了两个修改:(a)删除/d e v/z e r o的o p e n条语句,(b)将m m a p调用修改成下列形式:if(area=mmap(0,SIZE,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED,-1,0)=(caddr_t)-1)在此调用中,指定了M A P _ A N O N标志,并将文件描述符设置为 1。程序1 4-1 2的其余部分则不加改变。14.10 客户机

31、-服务器属性下面详细说明客户机和服务器的属性,这些属性受到它们之间所使用的 I P C的不同类型的影响。最简单的关系类型是使客户机 f o r k并执行所希望的服务器。在 f o r k之前先创建两个单向管道以使数据可在两个方向传输。图 1 4-8是这种形式的一个例子。被执行的服务器可能是设置-用户-I D的程序,这使它具有了特权。查看客户机的实际用户 I D就可以决定客户机的身份。(回忆8.9节,从中可了解到在e x e c前后实际用户I D和实际组I D并没有改变。)在这种安排下,可以构筑一个“开放式服务器”(1 5.4节即提供了这种客户机和服务器的一种实现)。它为客户机开放文件而不是客户

32、机调用o p e n函数。这样就可以增加在正常的U N I X用户/组/其他许可权之上或之外的附加的许可权检查。假定服务器是设置-用户-I D程序,这给予了它附加的许可权(很可能是 r o o t许可权)。服务器用客户机的实际用户 I D以决定是否给予它对所要求的文件的存取。使用这种方式,可以构筑一个服务器,它允许某种用户通常没有的存取权。在此例子中,因为服务器是父进程的子进程,所以它能做的一切是将文件内容传送给父进程。这种方式对一般文件工作得很好,同时,也可被用于专用设备文件。我们希望能做的是使服务器打开所要的文件,并将文件描述符送回。父进程可向子进程传送打开文件描述符,而子进程则不能向父进

33、程传回一个描述符(除非使用将在下一章介绍的专门编程技术)。下一种服务器类型已显示于图 1 4-1 2中,服务器是一个精灵进程,客户机则用某种形式的第1 4章进程间通信3 5 1下载I P C与其联系。可以将管道用于这种形式的客户机-服务器关系。要求有一种命名的 I P C,例如F I F O或消息队列。对于F I F O,如果服务器必需将数据送回客户机,则对每个客户机都要有单独使用的F I F O。如果客户机-服务器应用程序只有客户机向服务器送数据,则只需要一个众所周知的F I F O。(系统V行式打印机假脱机程序使用这种形式的客户机-服务器。客户机是l p(1)命令,服务器是l p s c

34、h e d进程。因为只有从客户机到服务器的数据流,没有任何数据需送回客户机,所有只需使用一个F I F O。使用消息队列则存在多种可能性:(1)在服务器和客户机之间可以只使用一个队列,使用每个消息的类型字段指明谁是消息的接受者。例如,客户机可以用类型字段为 1发送它们的消息。在要求之中应包括客户机的进程I D。此后,服务器在发送响应消息时,将类型字段设置为客户机的进程 I D。服务器只接受类型字段为1的消息(m s g r c v的第四个参数),客户机则只接受类型字段等于它们的进程I D的消息。(2)另一种方法是每个客户机使用一个单独的消息队列。在向服务器发送第一个请求之前,每个客户机先创建它

35、自己的消息队列,创建时使用关键字 I P C _ P R I VAT E。服务器也有它自己的队列,其关键字或标识符是所有客户机知道的。客户机将其第一个请求送到服务器的众所周知的队列上,该请求中应包含其客户机消息队列的队列 I D。服务器将其第一个响应送至客户机队列,此后的所有请求和响应都在此队列上交换。使用这种技术的一个问题是:每个客户机专用队列通常只有一个消息在其中或者是对服务器的一个请求,或者是对客户机的响应。这似乎是对有限的系统资源(消息队列)的浪费,可以用一个F I F O来代替。另一个问题是服务器需从多个队列读消息。对于消息队列,s e l e c t和p o l l都不起作用使用消

36、息队列的这两种技术都可以用共享存储段和同步方法(信号量或记录锁)实现。使用共享存储段的问题是,一次只能有一个消息在共享存储段中类似于队列限制为只能有一个消息。为此,在使用共享存储I P C时,通常每个客户机使用一个共享存储段。这种类型的客户机-服务器关系(客户机和服务器是无关系进程)的问题是:服务器如何准确地标识客户机。除非服务器正在执行一种非特权操作,否则服务器知道谁是客户机是很重要的。例如,若服务器是一个设置-用户-I D程序,就有这种要求。虽然,所有这几种形式的I P C都经由内核,但是它们并未提供任何措施使内核能够标识发送者。对于消息队列,如果在客户机和服务器之间使用一个专用队列(于是

37、一次只有一个消息在该队列上),那么队列的m s g _ l s p i d包含了对方进程的进程I D。但是当客户机将请求发送给服务器时,我们想要的是客户机的有效用户I D,而不是它的进程I D。现在还没有一种可移植的方法,在已知进程I D情况下用其可以得到有效用户 I D。(确实,内核在进程表项中保持有这两种值,但是除非彻底检查内核存储空间,否则已知一个,无法得到另一个。)我们将在1 5.5.2中使用下列技术,使服务器可以标识客户机。同样的技术也可用于 F I F O、消息队列、信号量或共享存储。下面的说明具体针对按图 1 4-1 2中的方式使用F I F O情况。客户机必须创建它自己的F I

38、 F O,并且设置F I F O的文件存取许可权,使得只允许用户-读,用户-写。假定服务器具有超级用户特权(或者它很可能并不关心客户机的真实标识),所以服务器仍可读、写此F I F O。当服务器在众所周知的 F I F O上接受到客户机的第一个请求时(它应当包含客户机专用F I F O的标识),服务器调用针对客户机专用F I F O的s t a t或f s t a t。服务器所采用的假设是;客户机的有效用户I D是F I F O的所有者(s t a t结构的s t _ u i d字段)。服务器验证该F I F O只有用户-读、用户-写许可权。服务器还应检查是该 F I F O的三个时间量(s

39、t a t结构中的s t _ a t i m e,s t _ m t i m e和s t _ c t i m e字段),要检查它们与当前时间是否很接近(例如不早于当前时间 1 5秒或3 0秒)。如果3 5 2U N I X环境高级编程下载一个有预谋的客户机可以创建一个 F I F O,使另一个用户成为其所有者,并且设置该文件的许可权为用户-读和用户-写,那么在系统中就存在了其他基础性的安全问题。为了在系统V IPC中应用这种技术,回想一下与每个消息队列、信号量、以及共享存储段相关的i p c _ p e r m结构,其中c u i d和c g i d字段标识I P C结构的创建者。以F I F

40、 O为例,服务器应当要求客户机创建该I P C结构,并使客户机将存取权设置为只允许用户-读和用户-写。服务器也应检验与该I P C相关的时间量与当前时间是否很接近(因为这些 I P C结构在显式地删除之前一直存在)。在1 5.5.1节中,将会看到进行这种身份验证工作的一种更好方法是内核提供客户机的有效用户I D和有效组I D。S V R 4在进程之间传送文件描述符时可以做到这一点。1 4.11 小结本章详细说明了进程间通信的多种形式;管道、命名管道(F I F O)以及另外三种I P C形式,通常称之为系统V IPC消息队列、信号量和共享存储。信号量实际上是同步原语而不是I P C,常用于共享

41、资源的同步存取,例如共享存储段。对于管道,说明了 p o p e n的实现,说明了协同进程,以及使用标准I/O库缓存机制时可能遇到的问题。在时间方面,对消息队列与流管道、信号量与记录锁做了比较后,提出了下列建议:学会使用管道和F I F O,因为在大量应用程序中仍可有效地使用这两种基本技术。在新的应用程序中,要尽可能避免使用消息队列以及信号量,而应当考虑流管道和记录锁,因为它们与 U N I X内核的其他部分集成得要好得多。共享存储段有其应用场合,而 m m a p函数(见1 2-9节)则可能在以后的版本中起更大作用。下一章将介绍一些更先进的I P C形式,它们由更加新的系统,例如S V R

42、4和4.3+B S D提供。习题1 4.1在在程序1 4-2中父进程代码的末尾,如删除w a i t p i d前的c l o s e,结果将如何?1 4.2在在程序1 4-2中父进程代码的末尾,如删除w a i t p i d,结果将如何?1 4.3在如果p o p e n的参数是一个不存在的命令会有什么结果?编写一段程序测试一下。1 4.4在删除程序1 4-9中的信号量处理程序,执行程序并终止子进程。输入一行后,怎样能说明父进程是由S I G P I P E终止的?1 4.5在将程序1 4-9中进行管道读、写的r e a d和w r i t e用标准I/O库代替。14.6在POSIX.1加

43、入waitpid函数的理由之一是POSIX.1前的大多数系统不能处理下面的代码。if(fp=popen(/bin/true,r)=NULL).if(rc=system(sleep 100)=-1).if(pclose(fp)=-1).若在这段代码中不使用w a i t p i d函数会如何?用w a i t代替呢?1 4.7在当一个管道被写者关闭后,解释s e l e c t和p o l l如何处理该管道的输入描述符?当一个管道的读端被关闭时,请重做此习题以查看该管道的输出描述符。编两个测试程序,一个用s e l e c t一个用p o l l,并确定答案是否正确。1 4.8在如果p o p

44、e n以t y p e为r执行c m d s t r i n g并将结果写到标准出错输出,结果如何?1 4.9在p o p e n会使得s h e l l执行它的c m d s t r i n g参数,当c m d s t r i n g终止时会产生什么结果?(提第1 4章进程间通信3 5 3下载示:画出包含的所有进程。)1 4.1 0在大多数U N I X系统允许读写F I F O,但是P O S I X.1特别声明没有定义为读写而打开F I F O。请用非阻塞方法实现为读写而打开F I F O。1 4.11在除非文件包含敏感或机密数据,否则允许其他用户读文件不会造成损害。但是,如果一个恶意

45、进程读取了被一个服务器和几个客户机进程使用的消息队列中的一条消息后会有什么结果?恶意进程需要知道哪些信息就可以读消息队列?1 4.1 2在编写一段程序完成下面的工作:循环五次创建一个消息队列,并打印队列的标识符,然后删除队列。接着再循环五次利用关键字I P C _ P R I VAT E创建消息队列并将一条消息放在队列中,程序终止后用i p c s(1)查看消息队列。解释队列标识符的变化。1 4.1 3在描述如何在共享存储段中建立一个数据对象的连接列表。列表指针如何保存?1 4.1 4在画出程序1 4-1 2的变量i在父进程和子进程中随时间变化的值。由 u p d a t e函数返回该值,其类

46、型为长整型,保存在共享存储区。假设f o r k后子进程先运行。1 4.1 5在使用1 4.9节的s h m X X X函数代替共享存储映射区重写程序1 4-1 2。1 4.1 6在使用1 4.8节系统V提供的信号量函数重写程序1 4-1 2实现父进程与子进程间的交替。1 4.1 7在使用建议性记录锁定方法重写程序1 4-1 2实现父进程与子进程间的交替。1 4.1 8在解释m m a p函数的文件描述符参数如何在 4.3+B S D系统匿名存储映射方式下允许不相关进程间的存储共享。3 5 4U N I X环境高级编程下载下载第1 5章高级进程间通信15.1 引言上一章说明了各种U N I X

47、系统提供的I P C经典方法,包括:管道、F I F O、消息队列、信号量和共享存储。本章介绍某些高级的I P C以及它们的应用方法,包括:流管道和命名流管道。使用这些机制,可以在进程间传送打开文件描述符。在分别为每一个客户进程提供一个通道的系统中,这些通信机制使客户进程能与精灵服务进程会合。4.2 B S D和S V R 3.2最早提供这些高级形式的I P C,但是至今尚未广泛使用,也缺少参考文献。本章中很多思想来自 P r e s s o t t o和R i t c h i e1 9 9 0的论文。15.2 流管道流管道是一个双向(全双工)管道。单个流管道就能向父、子进程提供双向的数据流。

48、图1 5-1显示了观察流管道的两种方式。它与图 1 4-1的唯一区别是双向箭头连线,因为流管道是全双工的。图15-1 观察流管道的两种方式实例下面用一个流管道再次实现了程序 1 4-9的协作进程实例。程序1 5-1是新的m a i n函数。a d d 2协作进程与程序1 4-8中的相同。程序1 5-1调用了创建一个流管道的新函数s _ p i p e。(下面将说明该函数的S V R 4和4.3+B S D版本。)程序15-1 用流管道驱动a d d 2过滤进程的程序用户进程用户进程流管通内核或父程序只使用f d 0,子程序只使用fd1。因为流管道的每一端都是全双工的,所以父进程读、写f d 0

49、,而子程序将f d 1 复制到标准输入和标准输出。图1 5-2显示了由此构成的描述符。3 5 6U N I X环境高级编程下载s _ p i p e函数定义为与标准p i p e函数类似。它的调用参数与p i p e相同,但返回的描述符以读-写方式打开。实例S V R 4下的s _ p i p e函数程序1 5-2是s _ p i p e函数的S V R 4版本。它只是调用创建全双工管道的标准p i p e函数。程序15-2 s_pipe函数的S V R 4版本在系统V的早期版本中也可以创建流管道,但要进行的处理较多。有关在S V R 3.2下创建流管道的详细情况,请参阅S t e v e n

50、 s1 9 9 0。图1 5-3显示了S V R 4之下管道的基本结构。它主要是两个相互连接的流首。因为管道是一种流设备,故可将处理模块压入管道的任一一端。1 5.5.1节将用此技术提供一个可以装配的命名管道。实例4.3+B S D之下的s _ p i p e函数程序1 5-3是s _ p i p e函数的B S D版本。此函数在4.2 B S D及以后的各版本中起作用。它创建一对互连的U N I X域流套接口。自4.2 B S D开始,常规的管道已用此方式实现。但是,当调用 p i p e时,第一个描述符的写端和第二个描述符的读端都被关闭。为获得全双工管道,必须直接调用s o c k e t

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁