版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第15章高級進程間通信15.1引言上一章說明了各種UNIX系統(tǒng)提供的IPC經(jīng)典方法,包括:管道、FIFO、消息隊列、信號量和共享。本章介紹某些高級的IPC以及它們的應(yīng)用方法,包括:流管道和命名流管道。使用這些機制,可以在進程間傳送打開文件描述符。在分別為每一個客戶進程提供一個通道的系統(tǒng)中,這些通信機制使客戶進程能與精靈服務(wù)進程會合。 4.2BSD和SVR3.2最早提供這些高級形式的IPC,但是至今尚未廣泛使用,也缺少參考文獻。本章中很多來自 Pressotto和Ritchie1990的。15.2流管道流管道是一個雙向(全雙工)管道。單個流管道就能向父、子進程提供雙向的數(shù)據(jù)流。圖 15-1顯示了
2、觀察流管道的兩種方式。它與圖 14-1的唯一區(qū)別是雙向箭頭連線,因為流管道是全雙工的。圖15-1 觀察流管道的兩種方式實例下面用一個流管道再次實現(xiàn)了程序 14-9的協(xié)作進程實例。程序15-1是新的main函數(shù)。add2協(xié)作進程與程序14-8中的相同。程序15-1調(diào)用了創(chuàng)建一個流管道的新函數(shù)s_pipe。(下面將說明該函數(shù)的SVR4和4.3+BSD版本。)程序15-1 用流管道驅(qū)動add2過濾進程的程序用戶進程用戶進程或流管通內(nèi)核356UNIX環(huán)境高級編程父程序只使用fd0,子程序只使用fd1 。因為流管道的每一端都是全雙工的,所以父進程讀、寫fd0,而子程序?qū)d1到標準輸入和標準輸出。圖15
3、-2顯示了由此的描述符。第 15章 高級進程間通信357s_pipe函數(shù)定義為與標準pipe函數(shù)類似。它的調(diào)用參數(shù)與pipe相同,但返回的描述符以讀 -寫方式打開。實例 SVR4下的s_pipe函數(shù)程序15-2是s_pipe函數(shù)的SVR4版本。它只是調(diào)用創(chuàng)建全雙工管道的標準pipe函數(shù)。程序15-2 s_pipe函數(shù)的SVR4版本圖15-3顯示了SVR4之下管道的基本結(jié)構(gòu)。它主要是兩個相互連接的流首。因為管道是一種流設(shè)備,故可將處理模塊壓入管道的任一一端。15.5.1節(jié)將用此技術(shù)提供一個可以裝配名管道。實例 4.3+BSD之下的s_pipe函數(shù)程序15-3是s_pipe函數(shù)的BSD版本。此函數(shù)
4、在 4.2BSD及以后的各版本中起作用。它創(chuàng)建一對互連的UNIX域流套接口。程序15-3 s_pipe函數(shù)的BSD版本自4.2BSD開始,常規(guī)的管道已用此方式實現(xiàn)。但是,當調(diào)用 pipe時,第一個描述符的寫端和第二個描述符的讀端都被關(guān)閉。為獲得全雙工管道,必須直接調(diào)用socketpair。用戶進程流首流首內(nèi)核圖15-3 SVR4之下的管道在系統(tǒng)V的早期版本中也可以創(chuàng)建流管道,但要進行的處理較多。有關(guān)在 SVR3.2下創(chuàng)建流管道的詳細情況,請參閱Stevens1990。父進程子進程(協(xié)作進程)圖15-2 為協(xié)作進程安排的描述符358UNIX環(huán)境高級編程15.3傳送文件描述符在進程間傳送打開文件描
5、述符的能力非常有用。用此可以對客戶機 /服務(wù)器應(yīng)用進行不同的設(shè)計。它允許一個進程(一般是服務(wù)器)處理與打開一個文件有關(guān)的所有操作(涉及的細節(jié)可能是:將網(wǎng)絡(luò)名翻譯為網(wǎng)絡(luò)地址、撥號調(diào)制解調(diào)器、協(xié)商文件鎖等。)以及向調(diào)用進程返回一描述符,該描述符可被用于以后的所有 I/O函數(shù)。打開文件或設(shè)備的所有細節(jié)對客戶而言都是透明的。下面進一步說明“從一個進程向另一個進程傳送一打開文件描述符”的含義。回憶圖 3-2,其中顯示了兩個進程,它們打開了同一文件。雖然它們共享同一 v節(jié)點表,但每個進程都有它自己的文件表項。當從一個進程向另一個進程傳送一打開文件描述符時,想要發(fā)送進程和接收進程共享同一文件表項。圖15-4
6、顯示了所希望的安排。在技術(shù)上,發(fā)送進程實際上向接受進程傳送一個指向一打開文件表項的指針。該指針被分配存放在接收進程的第一個可用描述符項中。(注意,不要得到錯覺以為發(fā)送進程和接收進程中的描述符是相同的,通常它們是不同的。)這種情況與在fork之后,父、子進程完全共個打開文件表項相同(見圖 8-1)。當發(fā)送進程將描述符傳送給接收進程后,通常它關(guān)閉該描述符。發(fā)送進程關(guān)閉該描述符并不造成關(guān)閉該文件或設(shè)備,其原因是該描述符對應(yīng)的文件仍需為接收進程打開(即使接收進程尚未接收到該描述符)。圖15-4 從上一進程傳送一個打開文件至下一進程進程表項fd標志 ptr文件表 文件狀態(tài)標志當前文件位移v節(jié)點表v節(jié)點指
7、針v節(jié)點信息進程表項i節(jié)點信息fd標志 ptr當前文件長度4.2BSD支持傳送打開描述符,但其實施中有些錯誤。4.3BSD排除了這些錯誤。 SVR3.2及以上版本都支持傳送打開描述符。第 15章 高級進程間通信359下面定義本章使用的三個函數(shù)(第18章也將使用)以發(fā)送和接收文件描述符。本節(jié)將會給出對于SVR4和4.3+BSD的這三個函數(shù)的不同實現(xiàn)。#include ourhdr.h send_fd(pipefd,send_err(pipefd,filedes);s us, const char e*rrmsg);兩個函數(shù)返回:若成功則為0,若出錯則為-1recv_fd(pipefd, ssiz
8、e_t (u*serfunc)( , const void *, size_t); 返回:若成功則為文件描述符,若出錯則 0當一個進程(通常是服務(wù)器)希望將一個描述符傳送給另一個進程時,它調(diào)用 send_fd或 send_err。等待接收描述符的進程(客戶機)調(diào)用recv_fd。send_fd經(jīng)由流管道spipefd發(fā)送描述符filedes。send_err 經(jīng)由流管道spipefd發(fā)送errmsg和 sus字節(jié)。sus的值應(yīng)在1255之間客戶機調(diào)用recv_fd接收一描述符。如果一切正常(發(fā)送者調(diào)用了send_fd),則作為函數(shù)值返回非負描述符。否則,返回值是由 send_err發(fā)送的sus
9、(1255之間的一個值)。另外,如果服務(wù)器發(fā)送了一條出錯消息,則客戶機調(diào)用它自己的 userfunc處理該消息。userfunc的第一個參數(shù)是常數(shù)STDERR_FILENO,然后是指向出錯消息的指針及其長度??蛻魴C指定為UNIX的write函數(shù)。userfunc自己制定的協(xié)議。為發(fā)送一描述符, send_fd先發(fā)送兩實現(xiàn)了用于這三個函數(shù)的個0字節(jié),然后是實際描述符。為了發(fā)送一條出錯消息, send_err 發(fā)送errmsg,然后是1個0字節(jié),最后是s us字節(jié)的絕對值(1255)。recv_fd讀流管道中所有字節(jié)直至null字符。null字符之前的所有字符都送給調(diào)用者的 userfunc。re
10、cv_fd讀到的下一個字節(jié)是s us字節(jié)。若s us字節(jié)為0,那么一個描述符已傳送,否則表示沒有接收到描述符send_err函數(shù)在將出錯消息寫到流管道后,即調(diào)用send_fd函數(shù)。這示于程序15-4中。程序15-4 send_err函數(shù)360UNIX環(huán)境高級編程以下三節(jié)介紹了在SVR4、4.3BSD和4.3+BSD下,兩個函數(shù)send_fd和recv_fd的實際實現(xiàn)。15.3.1 SVR4在SVR4之下,文件描述符用兩個ioctl命令在一流管道換,這兩個命令是: I_SENDFD和I_RECVFD。為了發(fā)送一描述符,將ioctl的第三個參數(shù)設(shè)置為實際描述符。這示于程序15-5中。程序15-5S
11、VR4的send_fd函數(shù)當接收一描述符時,ioctl的第三個參數(shù)是一指向strrecvfd結(jié)構(gòu)的指針。recv_fd讀流管道直到接收到雙字節(jié)協(xié)議的第一個字節(jié)( null字節(jié))當發(fā)出帶I_RECVFD命令的ioctl時,在流讀首處的第一條消息應(yīng)當是一個描述符,它是由 I_SENDFD發(fā)來的,或者得到一條出錯消息。這示于程序15-6中。程序15-6 SVR4的recv_fd函數(shù)高級進程間通信361第 15章15.3.2 4.3BSD不幸的是,對于4.3BSD以及在其基礎(chǔ)上構(gòu)造的SunOS和Ultrix,以及從4.3BSD Reno開始的后續(xù)版本必須提供不同的實現(xiàn)。為了交換文件描述符,調(diào)用send
12、msg(2)和recvmsg(2)函數(shù)。這兩個函數(shù)的參數(shù)中都有一個指向m s g h d r的指針,該結(jié)構(gòu)包含了所有關(guān)于要發(fā)送和接收消息的信息。該結(jié)構(gòu)定義在 頭文件中,在BSD4.3之下,其樣式是:362UNIX環(huán)境高級編程頭兩個元素通常用于在網(wǎng)絡(luò)連接上發(fā)送數(shù)據(jù)報文,在這里,目的地址可以由每個數(shù)據(jù)報文指定。下面兩個元素使可以指定緩存的數(shù)組(散布讀和寫),這如同對readv和writev函數(shù)(見12.7節(jié))的說明一樣。最后兩個元素處理存取權(quán)的傳送和接收。當前唯一定義的存取權(quán)是文件描述符。存取權(quán)僅可一個UNIX域套接口傳送(即在4.3BSD之為流管道所使用的)。為了發(fā)送或接收一文件描述符,將msg
13、_accrights設(shè)置為指向該整型描述符,將msg_accrightslen設(shè)置為描述符的長度(即整型的長度)。僅當此長度非0時,才傳送或接收描述符。程序15-7是4.3BSD的send_fd函數(shù)。程序15-7 4.3BDS的send_fd函數(shù)第 15章 高級進程間通信363在sendmsg調(diào)用中,發(fā)送雙字節(jié)協(xié)議數(shù)據(jù)( null和sus字節(jié))和描述符。為了接收一文件描述符,從流管道讀,直至讀到 null字節(jié),它位于最后的sus字節(jié)之前。 null字節(jié)之前是一條出錯消息,它來自發(fā)送者。這示于程序15-8。程序15-8 4.3BSD的recv_fd函數(shù)364UNIX環(huán)境高級編程注意,該程序總是準
14、備接收一描述符(在每次調(diào)用 recvmsg之前,設(shè)置msg_accrights和 msg_accrightslen),但是僅當在返回時msg_accrightslen非0,才確實接收到一描述符。15.3.3 4.3+BSD從4.3BSD Reno開始,更改了msghdr結(jié)構(gòu)的定義。在以前版本中被稱之為“存取權(quán)”的最后兩個元素改稱為“輔助數(shù)據(jù)”。另外,在該結(jié)構(gòu)結(jié)束處增加了一個新成員msg_flags。現(xiàn)在,msg_control字段指向一個cmsghdr(控制消息頭)結(jié)構(gòu)。為了發(fā)送一文件描述符,將cmsg_len設(shè)置為cmsghdr結(jié)構(gòu)長度加一個整型(描述符)的長度。將cmsg_level設(shè)置為
15、SOL_SOCKET,cmsg_type設(shè)置為SCM_RIGHTS,這表明正在傳送的是存取權(quán)( SCM表示套接口級控制消息)。實際描述符的存放位置緊隨在 cmsy_type字段之后,使用CMSG_DATA宏以獲得指向該整型數(shù)的指針。程序15-9示出了4.3BSD Reno之下的send_fd函數(shù)。程序15-9 4.3BSD的send_fd函數(shù)第 15章 高級進程間通信365為了接收一描述符(見程序15-10),為cmsghdr結(jié)構(gòu)和一描述符分配了足夠的區(qū),設(shè)置msg_control使其指向所分配到的區(qū),然后調(diào)用recvmsg。程序15-10 4.3BSD Reno的recv_fd函數(shù)366UN
16、IX環(huán)境高級編程15.4open服務(wù)器第1版目前,使用文件描述符傳送技術(shù)開發(fā)了一個open服務(wù)器:它是一個可執(zhí)行程序,由一個進程執(zhí)行以打開一個或多個文件。該服務(wù)器不是將文件送回調(diào)用進程,而是送回一個打開文件描述符。這使該服務(wù)器對任何類型的文件(例如調(diào)制解調(diào)器線或網(wǎng)絡(luò)連接)而不單是普通文件都能起作用。這也意味著,用 IPC交換最小量的信息 從客戶機到服務(wù)器傳送文件名和打開方式,而從服務(wù)器到客戶機返回描述符。文件內(nèi)容則不需用IPC傳送。將服務(wù)器設(shè)計成一個單獨的可執(zhí)行程序有很多優(yōu)點:任一客戶機都易于和服務(wù)器聯(lián)系,這類似于客戶機調(diào)用一庫函數(shù)。不需要將一特定服務(wù)編碼在應(yīng)用程序中,而是設(shè)計一種可供重用的設(shè)
17、施。如若需要更改服務(wù)器,那么也只影響一個程序。相反,更新一庫函數(shù)可能要更改調(diào)用此庫函數(shù)的所有程序(用連編程序重新連接)。共享庫函數(shù)可以簡化這種更新。(3) 服務(wù)器可以是設(shè)置-用戶-ID程序,于是使其具有客戶機沒有的附加權(quán)。注意,一第 15章 高級進程間通信367個庫函數(shù)(或共享庫函數(shù))不能提供這種能力??蛻魴C創(chuàng)建一流管道,然后調(diào)用 fork和exec以調(diào)用服務(wù)器。客戶機經(jīng)流管道發(fā)送請求,服務(wù)器經(jīng)管道回送響應(yīng)。定義客戶機和服務(wù)器間的協(xié)議如下:客戶機經(jīng)流管道向服務(wù)器發(fā)送下列形式的請求:open 0是open函數(shù)的第二個參數(shù),以十進制表示。該請求字符串以null字節(jié)結(jié)尾。服務(wù)器調(diào)用send_fd 或
18、send_err回送一打開描述符或一條出錯消息。這是一個進程向其父進程發(fā)送一打開描述符的實例。 15.6節(jié)將修改此實例,其中使用了一個精靈服務(wù)器,它將一個描述符發(fā)送給完全無關(guān)的進程。程序15-11是頭文件open.h,它包括標準系統(tǒng)頭文件,并且定義了各個函數(shù)原型。程序15-11 open.h頭文件程序15-12是main函數(shù),其中包含一個循環(huán),它先從標準輸入讀一個路徑名,然后將該文至標準輸出。它調(diào)用函數(shù)csopen以與open服務(wù)器聯(lián)系,從其返回一打開描述符。件程序15-12 main函數(shù)368UNIX環(huán)境高級編程程序15-13是函數(shù)csopen,它先創(chuàng)建一流管道,然后進行服務(wù)器的fork和e
19、xec操作。程序15-13csopen函數(shù)子進程關(guān)閉管道的一端,父進程關(guān)閉另一端。子進程也為它所執(zhí)行的服務(wù)器將管道的一端到其標準輸入和標準輸出 0(另一種可選擇的方案是將描述符fd1的ASCII 表示形式作為一個參數(shù)傳送給服務(wù)器。)父進程將請求發(fā)送給服務(wù)器,請求中包含路徑名和打開方式。最后,父進程調(diào)用 recv_fd以返回描述符或錯誤消息。如果服務(wù)器返回一錯誤消息則調(diào)用write,向標準出錯輸出該消息。現(xiàn)在,觀察 open服務(wù)器。其程序是 opend,它由子進程執(zhí)行(見程序 15 - 13 )。先觀察第 15章 高級進程間通信369opend.h頭文件(見程序15-14),它包括了系統(tǒng)頭文件,
20、并且說明了全局變量和函數(shù)原型。程序15-14 opend.h頭文件main函數(shù)(見程序15-15)經(jīng)流管道(它的標準輸入)讀來自客戶機的請求,然后調(diào)用函數(shù)request。程序15-15 main函數(shù)程序15-16中的request 函數(shù)承擔全部工作。它調(diào)用函數(shù) buf_args將客戶機請求分解成標準 argv型的參數(shù)表,然后調(diào)用函數(shù)cli_args處理客戶機的參數(shù)。如果一切正常,則調(diào)用open打開相應(yīng)文件,接著調(diào)用send_fd,經(jīng)由流管道(它的標準輸出)將描述符回送給客戶機。如果出錯則調(diào)用send_err回送一則出錯消息,其中使用了前面說明的客戶機-服務(wù)器協(xié)議。客戶機請求是一個空的中斷的字符
21、串,其參數(shù)由空格分隔。程序 15-17中的buf_args函數(shù)將字符串分解成標準argv型參數(shù)表,并調(diào)用用戶函數(shù)處理參數(shù)。本節(jié)稍后及第18章將用到該函數(shù)。使用ANSI C函數(shù)strtok將字符串分割成參數(shù)。程序15-16 request函數(shù)370UNIX環(huán)境高級編程程序15-17buf_args函數(shù)第 15章 高級進程間通信371buf_args調(diào)用的服務(wù)器函數(shù)是cli_args(見程序15-18)。它驗證客戶機發(fā)送的參數(shù)是否正確,然后將路徑名和打開方式存放在全局變量中。這樣也就完成了open服務(wù)器,它由客戶機執(zhí)行fork和exec而調(diào)用。在fork之前創(chuàng)建了一個流管道,然后客戶機和服務(wù)器用其
22、進行通信。在這種安排下,每個客戶機都有一服務(wù)器。在下一節(jié)觀察了客戶機-服務(wù)器連接后,在15.6節(jié)重新實現(xiàn)一個open服務(wù)器,其中用一個精靈進程作為服務(wù)器,所有客戶機都與其進行聯(lián)系。程序15-18 cli_args函數(shù)15.5客戶機-服務(wù)器連接函數(shù)對于相關(guān)進程(例如,父進程進程)之間的 IPC,流管道非常有用。前節(jié)所述的open服務(wù)器使用未命名的流管道能從子進程向父進程傳送文件描述符。但是當處理無關(guān)進程時(例如,若服務(wù)器是一精靈進程),則需要使用有名的流管道??梢韵葮?gòu)造一未命名流管道(用s_pipe 函數(shù)),然后對每一端加上一文件系統(tǒng)路徑名。精靈進程服務(wù)器將只創(chuàng)建流管道的一端,并對該端加上一名字
23、。這樣,無關(guān)的客戶機可以向服務(wù)者的流管道端發(fā)送消息,從而與精靈進程會聚。這類似于圖 14-11中所示的情況,在該圖中客戶機使用FIFO發(fā)送它們的請求。一種更好的方法是:服務(wù)器創(chuàng)建一名字公開的流管道的一端,然后客戶機連接至該端。另外,每次一個新客戶機連至服務(wù)器名流管道時,就在客戶機和服務(wù)器之間創(chuàng)建一條全新的流管道。這樣,每次一個新客戶機連接至服務(wù)器,以及客戶機終止時,服務(wù)器都會得到通知。 SVR4和4.3+BSD都支持這種形式的IPC。本節(jié)將開發(fā)三個函數(shù),客戶機 -服務(wù)器可以使用這些函數(shù)以建立上述針對每個客戶機的連接。#include ourhdr.h serv_listen(const ch
24、anram*e);返回:若成功則返回為文件描述符,若出錯則 0372UNIX環(huán)境高級編程首先,一個服務(wù)器應(yīng)當宣布,它愿意聽取客戶機在一個眾所名字上的連接,該名字是在文件系統(tǒng)中的一個路徑名。為此調(diào)用 serv_listen,其參數(shù)name是服務(wù)器的眾所名字??蛻魴C希望與服務(wù)器連接時使用此名字。該函數(shù)的返回值是命名流管道服務(wù)器端的文件描述符。一旦服務(wù)器已調(diào)用serv_listen,它將調(diào)用serv_accept等待客戶連接到達。#include ourhdr.h serv_accept(tenfd, uid_t u*idptr);返回:若成功則返回為文件描述符,若出錯則 0listenfd是ser
25、v_listen返回的描述符。在客戶機連接到服務(wù)器眾所的名字上之前,此函數(shù)并不返回。當客戶機連接至服務(wù)器時,自動創(chuàng)建一條全新的流管道,其新描述符作為該函數(shù)的值返回。另外,客戶機的有效用戶ID通過指針uidptr客戶機為與服務(wù)器連接只需調(diào)用cli_conn函數(shù)。#include ourhdr.h cli_conn(const ch a nram*e);返回:若成功則返回為文件描述符,若出錯則 0客戶指定的name應(yīng)當與服務(wù)器調(diào)用serv_listen時宣布的相同。返回的描述符務(wù)器的流管道連接至服使用上述三個函數(shù),就可編寫服務(wù)器精靈進程,它可以管理任一數(shù)量的客戶機。唯一的限制是單個進程可用的描述符
26、數(shù),服務(wù)器對于每一個客戶機連接都需要一個描述符。因為這些函數(shù)處理的都是普通文件描述符,所以服務(wù)器使用 select或poll就可在所有客戶機之間多路轉(zhuǎn)接 I/O請求。最后,因為客戶機-服務(wù)器連接都是流管道,所以可以經(jīng)由連接傳送打開描述符。下面兩節(jié)將說明在SVR4和4.3+BSD之下這三個函數(shù)的實現(xiàn)。第 18章開發(fā)一個通用的連接服務(wù)器時,也將使用這三個函數(shù)。15.5.1 SVR4SVR4提供裝配的流以及一個名為 connld的流處理模塊,用其可以提供與服務(wù)器有唯一連接名流管道。裝配流和connld模塊是由Presotto和Ritchie1990為Researc的,后來由SVR4采用。IX系統(tǒng)開發(fā)
27、首先,服務(wù)器創(chuàng)建一未命名流管道,并將流處理模塊connld壓入一端。圖15-5顯示了這一處理結(jié)果。然后,使壓入 c o n n l d 的一端具有一路徑名。S V R 4 提供f a t t a c h 函數(shù)實現(xiàn)這一點。任一進程(例如客戶機)打開此路徑名就名端。該管道程序15-19使用了20余行代碼實現(xiàn)serv_listen函數(shù)。用戶進程流首流首內(nèi)核圖15-5 在一端壓入connld模塊后的流管道第 15章 高級進程間通信373程序15-19SVR4的serv_listen函數(shù)當另一進程對管道名端( connld模塊壓入端)調(diào)用open時,發(fā)生下列處理過程:創(chuàng)建一個新管道。該新管道的一個描述符
28、作為open的返回值回送給客戶機。另一個描述符在命名管道的另一端(亦即不是壓入 connld的端)傳送給服務(wù)器。服務(wù)器以帶I_RECVFD命令的ioctl接受該新描述符。假定服務(wù)器用fattach函數(shù)加到其管道的眾所調(diào)用:fd=open(/tmp/serv1, O_RDWR); 并返回后產(chǎn)生的結(jié)果。的名字是/tmp/serv1。圖15-6顯示了客戶機圖15-6 客戶機-服務(wù)器在命名管道上的連接客戶機服務(wù)器流首流首流首流首內(nèi)核374UNIX環(huán)境高級編程客戶機和服務(wù)器之間的管道是open創(chuàng)建的,被打開的路徑名實際上是一命名管道,其中壓入了connld模塊??蛻魴C得到由open返回的文件描述符fd。
29、服務(wù)器處的新文件描述符是clifdl,它是由服務(wù)器在描述符fd0上以I_RECVFD命令調(diào)用ioctl而接收到的。一旦服務(wù)器在fd1上壓入了connld模塊,并對fd1附接上一個名字,它就不再使用fd1。服務(wù)器調(diào)用程序15-20中的serv_accept函數(shù)等待客戶機連接到達。程序15-20 SVR4的serv_accept函數(shù)在圖15-6中,serv_accept的第一個參數(shù)應(yīng)當是描述符fd0,serv_accept的返回值是描述符 clifdl。客戶機調(diào)用程序15-21中的cli_conn函數(shù)起動對服務(wù)器的連接。程序15-21 SVR4的cli_conn函數(shù)對返回的描述符是否一個流設(shè)備進行
30、了兩次檢查,以便處理服務(wù)器沒有起動,但該路徑名卻存在于文件系統(tǒng)中的情況。(在SVR4下,幾乎沒理由去調(diào)用cli_conn,而不第 15章 高級進程間通信375是直接調(diào)用 open。下一節(jié)將看到,在 BSD系統(tǒng)之下, cli_conn函數(shù)要復(fù)雜得多,因此編寫 cli_conn函數(shù)就很必要。)15.5.2 4.3+BSD在4.3+BSD之下,為了用UNIX域套接口連接客戶機和服務(wù)器,需要有一套不同的操作函數(shù)。因為應(yīng)用socket、bind、listen、accept和connect函數(shù)的大部分細節(jié)與其他網(wǎng)絡(luò)協(xié)議有關(guān)(參見Stevens1990),所以此處不詳細展開。程序15-22包含了serv_l
31、isten函數(shù)。它是服務(wù)器調(diào)用的第一個函數(shù)。程序15-224.3+BSD的serv_listen函數(shù)首先,調(diào)用socket函數(shù)創(chuàng)建一個UNIX域套接口。然后,填充sockeraddr_un結(jié)構(gòu),將一個眾的路徑名賦與該套接口。該結(jié)構(gòu)是調(diào)用bind函數(shù)的一個參數(shù)。然后調(diào)用listen以通知內(nèi)核:所本服務(wù)器正等待來自客戶機的連接。(listen的第二個參數(shù)是 5,它是最大的未決連接請求數(shù),因為SVR4也支持UNIX域套接口,所以本節(jié)所示代碼同樣可在SVR4之下工作。376UNIX環(huán)境高級編程內(nèi)核將這些請求對該描述符進行排隊。大多數(shù)實現(xiàn)強制該值的上限為 5。)客戶機調(diào)用cli_conn函數(shù)(見程序15
32、-23)起動與服務(wù)器的連接。程序15-23 4.3+BSD的cli_conn函數(shù)第 15章 高級進程間通信377調(diào)用socket函數(shù)以創(chuàng)建客戶端的UNIX域套接口,然后客戶機的名字填入socketaddr_un結(jié)構(gòu)。該路徑名的最后 5個字符是客戶機的進程ID(可以查證此結(jié)構(gòu)的長度是 14個字符,以避免UNIX域套接口早期實現(xiàn)的某些錯誤)。在路徑名已經(jīng)存在的情況下調(diào)用 unlink,然后再調(diào)用bind將一名字賦與客戶機的套接口,這就創(chuàng)建了文件系統(tǒng)中的路徑名,該文件的類型是套接口。接著調(diào)用 od,它關(guān)閉除user_read,user_write和user_execute以外的存取權(quán)。在serv_a
33、ccept中,服務(wù)器檢查該套接口的這些權(quán)和用戶ID,以驗證用戶的。然后,以服務(wù)器眾所與服務(wù)器的連接。的路徑名填充另一個socketaddr_un結(jié)構(gòu)。最后, connect函數(shù)起動創(chuàng)建每個客戶機與服務(wù)器的唯一連接是通過在 serv_accept函數(shù)中調(diào)用accept函數(shù)實現(xiàn)的(見程序15-24)。程序15-24 4.3+BSD的serv_accept函數(shù)378UNIX環(huán)境高級編程服務(wù)器在調(diào)用accept中堵塞以等待客戶機調(diào)用cli_conn。當accept返回時,其返回值是連向客戶機的全新的描述符(這類似于 S V R 4 中 connld模塊所做的)。另外, accept也通過其第二個參數(shù)(
34、指向socketaddr_un結(jié)構(gòu)的指針)返回客戶機賦與其套接口的路徑名(它包含客戶機的進程ID)。用null字節(jié)結(jié)束此路徑名,然后調(diào)用s。這使個套接口,其 user_execute??梢则炞C此路徑名確實是一權(quán) user_read,user_write和也驗證與該套接口相關(guān)的三個時間不超過30秒。(time函數(shù)返回自UNIX紀元經(jīng)過的時間和日期,它們都以秒計。)如果所有這些檢查都通過,則認為該客戶機的(其有效用戶ID)是該套接口的所有者。雖然這種檢查并不完善,但卻是現(xiàn)有系統(tǒng)所能做得最好的。(如果內(nèi)核能像SVR4 I_RECVFD做的那樣,將有效用戶ID返回給accept,那就更好一些。)圖15
35、-7顯示了cli_conn調(diào)用返回后的這種連接,假定服務(wù)器眾所請將此圖與圖15-6相比較。15.6open服務(wù)器第2版的名字是 /tmp/serv1。在15.4節(jié)中,客戶機調(diào)用fork和exec構(gòu)造了一個open服務(wù)器,它說明了如何從子程序向父程序傳送文件描述符。本節(jié)將開發(fā)一個精靈進程樣式的 open服務(wù)器。一個服務(wù)器處理所有客戶機的請求。由于避免使用了fork和exec,期望這一設(shè)計會更有效的。在客戶機和服務(wù)器之間仍將使用上一節(jié)說明的三個函數(shù): serv_listen、serv_accept和cli_conn。這一服務(wù)器將表明:一個服務(wù)器可以處理多個客戶機,為此使用的技術(shù)是12.5節(jié)中說明的
36、select和poll函數(shù)。本節(jié)所述的客戶機類似于15.4節(jié)中的客戶機。確實,文件main.c是完全相同的(見程序15-12)。在open h頭文件(見程序15-11)中則加了下面1行:#define CS_OPEN /home/stevens/open /* servers well-known name */ 因為在這里調(diào)用的是cli_conn而非fork和exec,所以文件open.c與程序15-13完全不同。這示于程序15-25中。程序15-25 csopen函數(shù)客戶機服務(wù)器套接口套接口套接口內(nèi)核圖15-7 UNIX域套接口上客戶機-服務(wù)器連接高級進程間通信379第 15章客戶機與服務(wù)
37、器之間使用的協(xié)議仍然相同。讓先查看服務(wù)器。頭文件opend.h(見程序15-26)包括了標準頭文件,并且說明了全局變量和函數(shù)原型。程序15-26open.h頭文件因為此服務(wù)器處理所有客戶機,所以它必須保存每個客戶機連接的狀態(tài)。這是用定義在opend.h頭文件中的cnt數(shù)組實現(xiàn)的。程序15-27定義了三個處理此數(shù)組的函數(shù)。380UNIX環(huán)境高級編程程序15-27處理cnt數(shù)組的三個函數(shù)第一次調(diào)用cnt_add時,它調(diào)用cnt_alloc、cnt_alloc又調(diào)用malloc為該數(shù)組的10個登記項分配空間。在這10個登記項全部用完后,再調(diào)用cnt_add,使realloc分配附加空間。依靠這種動態(tài)
38、空間分配,無需在編譯時限制cnt數(shù)組的長度。第 15章 高級進程間通信381如果出錯,那么因為假定服務(wù)器是精靈進程,所以這些函數(shù)調(diào)用log_函數(shù)(見附錄B)。 main函數(shù)(見程序15-28)定義全局變量,處理命令行選擇項,然后調(diào)用 loop函數(shù)。如果以-d選擇項調(diào)用服務(wù)器,則它以交互方式運行而非精靈進程。當測試些服務(wù)器時,使用交互運行方式。程序15-28 main函數(shù)loop函數(shù)是服務(wù)器的無限循環(huán)。給出該函數(shù)的兩種版本。程序 15-29是使用select的一種版本。(在4.3+BSD和SVR4之下工作),程序15-30是使用poll(用于SVR4)的另一種版本。程序15-29 使用selec
39、t的loop函數(shù)382UNIX環(huán)境高級編程此函數(shù)調(diào)用serv_listen以創(chuàng)建服務(wù)器對于客戶機連接的端點。此函數(shù)的其余部分是一個循環(huán),它以select調(diào)用開始。在select返回后,兩個條件可能為真:(1) 描述符listenfd可能準備好讀,這意味著新客戶機已調(diào)用了cli_conn。為了處理這種情況。調(diào)用serv_accept,然后更新cnt數(shù)組以及與該新客戶機相關(guān)的簿記消息。(作為select第一個參數(shù)的最高描述符。也使用中的cnt數(shù)組的最高下標。)(2) 一個現(xiàn)存的客戶機的連接可能準備好讀。這意味這下列兩事件之一:(a)該客戶機已經(jīng)終止,或( b)該客戶機已發(fā)送一新請求。如果 read返回0(文件結(jié)束),則可認為一客戶機終止。如果讀返回值大于0則可判定有一新請求需處理,調(diào)用request處理此新的客戶機請求。用allset描述符集當前使用的描述符。當新客戶機連至服務(wù)器時,此描述符集的適當位被打開。當該客戶機終止時,適當位就被關(guān)閉。因為客戶機的所有描述符都由內(nèi)核自動關(guān)閉(包括與服
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 師德師風警示教育活動總結(jié)6篇
- 工程信息管理體系
- 國開《可編程控制器應(yīng)用》形考任務(wù)五實驗1
- 2024年淮南聯(lián)合大學(xué)高職單招職業(yè)適應(yīng)性測試歷年參考題庫含答案解析
- 2022年6月7日陜西省省直事業(yè)單位廣播電視局面試真題及答案
- 中國人民大學(xué)會計系列教材·第四版《成本會計學(xué)》課件-第六章
- 濕紙巾發(fā)展趨勢分析報告
- 2024年隴西縣第一人民醫(yī)院高層次衛(wèi)技人才招聘筆試歷年參考題庫頻考點附帶答案
- 如何提起證券交易代理合同糾紛訴訟培訓(xùn)講學(xué)
- 2024年泰山護理職業(yè)學(xué)院高職單招職業(yè)適應(yīng)性測試歷年參考題庫含答案解析
- 《常見包材工藝簡介》課件
- 運輸管理與鐵路運輸
- 寧德時代社招測評題庫
- 統(tǒng)編版六年級語文上冊專項 專題11文言文閱讀-原卷版+解析
- 高中數(shù)學(xué)筆記總結(jié)高一至高三很全
- 011(1)-《社會保險人員減員申報表》
- 電廠C級檢修工藝流程
- 函授本科《小學(xué)教育》畢業(yè)論文范文
- 高考高中英語單詞詞根詞綴大全
- 藥用輔料聚乙二醇400特性、用法用量
- 《中小學(xué)機器人教育研究(論文)11000字》
評論
0/150
提交評論