網(wǎng)絡(luò)程序設(shè)計(jì)教材第四章 顧客服務(wù)員程序設(shè)計(jì)_第1頁
網(wǎng)絡(luò)程序設(shè)計(jì)教材第四章 顧客服務(wù)員程序設(shè)計(jì)_第2頁
網(wǎng)絡(luò)程序設(shè)計(jì)教材第四章 顧客服務(wù)員程序設(shè)計(jì)_第3頁
網(wǎng)絡(luò)程序設(shè)計(jì)教材第四章 顧客服務(wù)員程序設(shè)計(jì)_第4頁
網(wǎng)絡(luò)程序設(shè)計(jì)教材第四章 顧客服務(wù)員程序設(shè)計(jì)_第5頁
已閱讀5頁,還剩51頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、顧客服務(wù)員程序設(shè)計(jì)4.1 網(wǎng)絡(luò)服務(wù)模式近年來,在信息系統(tǒng)中廣泛使用的信息共享模型是顧客/服務(wù)器模型,這種計(jì)算模式迅速取代了以主機(jī)為主導(dǎo)的集中式計(jì)算方法。顧客/服務(wù)器計(jì)算具有自己的一組行業(yè)術(shù)語。表4-1列出了一些術(shù)語,這些術(shù)語經(jīng)常出現(xiàn)在對顧客/服務(wù)器產(chǎn)品和應(yīng)用的描述中。表4-1 顧客/服務(wù)器術(shù)語術(shù)語說明應(yīng)用程序編程接口(API)一組支持顧客/服務(wù)器之間進(jìn)行相互通信的函數(shù)和可調(diào)用程序顧客一個服務(wù)的請求方,通常是一個末端系統(tǒng),能夠從服務(wù)器處查詢信息中間件一組驅(qū)動程序、應(yīng)用程序編程接口或其它軟件,用于改善顧客/服務(wù)器之間的連接關(guān)系數(shù)據(jù)庫是一種把信息訪問限制于按照搜索條件選擇數(shù)據(jù)的數(shù)據(jù)庫服務(wù)器是一臺計(jì)算

2、機(jī),通常是一臺高性能工作站、小型機(jī)或大型機(jī),擁有供網(wǎng)絡(luò)中眾多用戶訪問的信息結(jié)構(gòu)化查詢語言(SQL)由IBM開發(fā)、由ANSI標(biāo)準(zhǔn)化的一種語言,用于對關(guān)系數(shù)據(jù)庫的尋址、創(chuàng)建、更新和查詢顧客/服務(wù)器環(huán)境中最基本元素是顧客和服務(wù)器。顧客通常是PC或工作站,為端用戶提供非常友好的界面,例如微軟的Windows等。服務(wù)器為顧客提供一組共享的用戶服務(wù)程序。最常見的是數(shù)據(jù)庫服務(wù)器,服務(wù)器能夠使很多顧客共享對同一信息源的訪問。除了顧客和服務(wù)器,組成顧客/服務(wù)器模型的第三個基本要素是網(wǎng)絡(luò)系統(tǒng)。顧客。服務(wù)器計(jì)算是分布式計(jì)算。用戶、應(yīng)用程序和資源是分布式的,用來響應(yīng)實(shí)際業(yè)務(wù)請求,并且它們通過局域網(wǎng)、廣域網(wǎng)或Inter

3、net連接起來。顧客/服務(wù)器模型與分布式處理有很多不同點(diǎn),主要有:在用戶自己的系統(tǒng)中為該用戶提供界面友好的應(yīng)用程序。這使得用戶可以在很大程度上控制時間安排和計(jì)算機(jī)使用類型,并使得部門管理者具有響應(yīng)本地需求的能力。盡管應(yīng)用是分散的,但仍然強(qiáng)調(diào)數(shù)據(jù)的集中以及很多網(wǎng)絡(luò)管理和使用功能的集中。對于用戶組織和廠商來說,他們有一個共同的承諾,使系統(tǒng)開放和模塊化。這意味著用戶在選擇產(chǎn)品和混合使用來自眾多廠家的設(shè)備時具有很大的選擇性。網(wǎng)絡(luò)互聯(lián)是操作的基礎(chǔ),網(wǎng)絡(luò)管理和網(wǎng)絡(luò)安全在組織和操作系統(tǒng)中具有很高的優(yōu)先權(quán)。4.1.1 顧客/服務(wù)器應(yīng)用顧客/服務(wù)器體系結(jié)構(gòu)的核心是應(yīng)用程序級任務(wù)在顧客和服務(wù)器之間的分配。圖4-1

4、給出了這個模型的一般情況。無論是顧客還是服務(wù)器,最基本的軟件是運(yùn)行在硬件平臺上的操作系統(tǒng),顧客的平臺和操作系統(tǒng)可能和服務(wù)器的不同。事實(shí)上,在網(wǎng)絡(luò)環(huán)境下,可能會有很多不同類型的顧客平臺和操作系統(tǒng)以及很多類型的服務(wù)器平臺和操作系統(tǒng)。只要特定的顧客和服務(wù)器共享相同的通信協(xié)議并支持相同的應(yīng)用程序,低層的細(xì)節(jié)不必考慮。顧客顧客服務(wù)器服務(wù)器請求/應(yīng)答表示服務(wù)請求/應(yīng)答表示服務(wù)應(yīng)用邏輯(服務(wù)器部分)應(yīng)用邏輯(顧客部分)應(yīng)用邏輯(服務(wù)器部分)應(yīng)用邏輯(顧客部分)通信軟件通信軟件通信軟件通信軟件協(xié)議交互服務(wù)器操作系統(tǒng)顧客操作系統(tǒng)協(xié)議交互服務(wù)器操作系統(tǒng)顧客操作系統(tǒng)硬件平臺硬件平臺硬件平臺硬件平臺圖4-1 顧客/服

5、務(wù)器體系結(jié)構(gòu)圖4-1 顧客/服務(wù)器體系結(jié)構(gòu)使顧客和服務(wù)器能夠交互的基礎(chǔ)是通信軟件,這種軟件主要例子是TCP/IP。所有這些支持軟件(通信軟件和操作系統(tǒng))的主要任務(wù)是,為分布式的應(yīng)用程序提供一個基本結(jié)構(gòu)。在理論上,應(yīng)用程序所執(zhí)行的實(shí)際功能可以針對顧客和服務(wù)器分割開來,方法是使平臺和網(wǎng)絡(luò)資源達(dá)到最優(yōu)化。且使用戶執(zhí)行各種任務(wù)及相互之間合作使用共享資源的能力達(dá)到最優(yōu)化。在某些情況下,這些都要求大批的應(yīng)用程序軟件在服務(wù)器上執(zhí)行,而在其它一些情況下,多數(shù)應(yīng)用程序邏輯上位于顧客端。顧客/服務(wù)器環(huán)境能夠成功的一個基本因素是用戶將系統(tǒng)當(dāng)作一個整體而與之打交道的方式。因此,顧客端的用戶界面的設(shè)計(jì)是十分重要的。在大

6、多數(shù)顧客/服務(wù)器系統(tǒng)中,都突出強(qiáng)調(diào)了要提供易于使用、易于學(xué)習(xí)、功能強(qiáng)大并且靈活的圖形用戶界面(GUI)。4.1.2 顧客/服務(wù)器應(yīng)用程序分類在顧客/服務(wù)器的通用框架中,對顧客和服務(wù)器的工作劃分有許多不同的實(shí)現(xiàn)方法。圖4-2針對數(shù)據(jù)庫應(yīng)用說明了可以以多種方式來分配處理過程,圖中概括了數(shù)據(jù)庫應(yīng)用的一些主要選項(xiàng)。當(dāng)然也存在其它的劃分方法,并且對于其它不同類型的應(yīng)用選項(xiàng)也可能具有不同的特點(diǎn)。服務(wù)器顧客服務(wù)器顧客表示邏輯表示邏輯應(yīng)用邏輯應(yīng)用邏輯數(shù)據(jù)庫邏輯數(shù)據(jù)庫邏輯DBMSDBMS(a) 基于主機(jī)的處理(a) 基于主機(jī)的處理服務(wù)器顧客服務(wù)器顧客表示邏輯表示邏輯應(yīng)用邏輯應(yīng)用邏輯數(shù)據(jù)庫邏輯數(shù)據(jù)庫邏輯DBMSD

7、BMS(b) 基于服務(wù)器的處理(b) 基于服務(wù)器的處理服務(wù)器顧客服務(wù)器顧客表示邏輯表示邏輯應(yīng)用邏輯應(yīng)用邏輯應(yīng)用邏輯應(yīng)用邏輯數(shù)據(jù)庫邏輯數(shù)據(jù)庫邏輯DBMSDBMS(c) 合作處理(c) 合作處理服務(wù)器顧客服務(wù)器顧客表示邏輯表示邏輯應(yīng)用邏輯應(yīng)用邏輯數(shù)據(jù)庫邏輯數(shù)據(jù)庫邏輯數(shù)據(jù)庫邏輯數(shù)據(jù)庫邏輯DBMSDBMS(d) 基于顧客的處理(d) 基于顧客的處理圖4-2 顧客/服務(wù)器應(yīng)用程序分類圖4-2 顧客/服務(wù)器應(yīng)用程序分類圖4-2描述了4種網(wǎng)絡(luò)服務(wù)類型,它們分別是:基于主機(jī)的處理:基于主機(jī)的處理并不是真正的用戶普遍認(rèn)同的顧客/服務(wù)器計(jì)算。而且,基于主機(jī)的處理是指傳統(tǒng)的大型機(jī)環(huán)境,實(shí)質(zhì)上所有的處理都是在一臺中心

8、主機(jī)上完成的。用戶接口通常是通過一臺啞終端,即使用戶在使用一臺微機(jī),用戶終端也是局限于終端仿真器的角色。基于服務(wù)器的處理:顧客/服務(wù)器配置的最基本的一類,即顧客端主要負(fù)責(zé)提供圖形化用戶界面,而實(shí)質(zhì)上所有的處理都是在服務(wù)器上完成的。這種配置是早期的顧客/服務(wù)器模式,尤其是部門級系統(tǒng)的典型。在這種配置背后的基本原理是用戶工作站最適合提供良好的用戶界面,并且數(shù)據(jù)庫和應(yīng)用程序很容易在中心系統(tǒng)上維護(hù)?;陬櫩偷奶幚恚涸诹硪粋€極端,實(shí)際上所有應(yīng)用處理可以全部在顧客端完成。一個例外是最適合在服務(wù)器上執(zhí)行的數(shù)據(jù)確認(rèn)例程和其它數(shù)據(jù)庫邏輯功能。一般地,某些更復(fù)雜的數(shù)據(jù)庫邏輯功能都位于顧客端。這種結(jié)構(gòu)可能是當(dāng)今使用

9、最普遍的顧客/服務(wù)器方式,使用戶能夠使用適合本地需要的應(yīng)用。合作處理:在合作處理配置方式中,應(yīng)用處理是以最優(yōu)化的方式來執(zhí)行的,充分利用了顧客和服務(wù)器兩方面的優(yōu)勢以及數(shù)據(jù)的分布性。這樣一種配置在設(shè)置和維護(hù)方面更加復(fù)雜,但從長遠(yuǎn)看,這種配置類型比其它類型可以為用戶更好的服務(wù)質(zhì)量和更高的網(wǎng)絡(luò)效率。圖4-2c和圖4-2d對應(yīng)的配置情況是在顧客端上有相當(dāng)大的一部分負(fù)載。這種所謂的“胖顧客”(fat client)模型已經(jīng)被像Powersoft公司的PowerBuilder和Gupta公司的SQL Windows這樣的應(yīng)用程序開發(fā)工具所采用。使用這些工具開發(fā)的應(yīng)用在范圍上是部門級的,支持25到150個用戶

10、。胖顧客的主要優(yōu)點(diǎn)是它充分利用了桌面功能,卸除了服務(wù)器上的應(yīng)用處理并使它們更加有效,不易發(fā)生瓶頸。然而,胖顧客策略也存在許多缺點(diǎn),隨著更多功能累加起來,快速地超出了桌面機(jī)器的容量,迫使機(jī)器進(jìn)行升級。如果模型擴(kuò)充,超出了部門的界限,合并了很多用戶,則必須安裝高性能局域網(wǎng)來支持瘦服務(wù)器和胖顧客之間大量的數(shù)據(jù)傳輸。最后,維護(hù)、升級或替換分布于數(shù)十臺或百臺桌面機(jī)的應(yīng)用程序是非常困難的。圖4-2b代表了一種瘦顧客(thin client)的方式,這種方式更近似地模仿了傳統(tǒng)的以主機(jī)為中心的方式,常常是使應(yīng)用程序從大型機(jī)環(huán)境發(fā)展到分布式環(huán)境的移植途徑,是目前流行的Internet網(wǎng)絡(luò)環(huán)境下的應(yīng)用程序開發(fā)模式

11、。4.1.3 三層顧客/服務(wù)器結(jié)構(gòu)傳統(tǒng)的顧客/服務(wù)器結(jié)構(gòu)包括兩級(或稱兩層):顧客層和服務(wù)器層。近年來,一種三層結(jié)構(gòu)變得日益流行,如圖4-3所示。在這種結(jié)構(gòu)中,應(yīng)用軟件分布在三種類型的機(jī)器上:用戶機(jī)器、中間層服務(wù)器以及后端服務(wù)器。用戶機(jī)器是顧客,在三層結(jié)構(gòu)中,它一般是一種瘦型顧客。中間層機(jī)器基本上是位于顧客和很多后端數(shù)據(jù)庫服務(wù)器之間的連接器。中間層機(jī)器能夠轉(zhuǎn)換協(xié)議,從一種類型的數(shù)據(jù)庫系統(tǒng)映像為另一種。另外,中間層機(jī)器能夠融合來自不同數(shù)據(jù)源的結(jié)果。最后,中間層機(jī)器也可以充當(dāng)桌面應(yīng)用程序和后端應(yīng)用程序之間的連接器。在中間層服務(wù)器和后端服務(wù)器之間的交互也遵從顧客/服務(wù)器的模式。因此,中間層服務(wù)器同時

12、充當(dāng)著顧客和服務(wù)器。顧客顧客中間層服務(wù)器中間層服務(wù)器(應(yīng)用程序服務(wù)器)后端服務(wù)器后端服務(wù)器后端服務(wù)器后端服務(wù)器圖4-3 三層顧客/服務(wù)器結(jié)構(gòu)圖4-3 三層顧客/服務(wù)器結(jié)構(gòu)4.1.4 中間件顧客/服務(wù)器產(chǎn)品的開發(fā)和使用缺少標(biāo)準(zhǔn)化,使得實(shí)現(xiàn)集成的、多廠商的、企業(yè)范圍的顧客/服務(wù)器配置變得困難,因?yàn)轭櫩?服務(wù)器方式的大多數(shù)優(yōu)點(diǎn)與其模塊化以及將平臺和應(yīng)用程序混合、協(xié)調(diào)起來提供商業(yè)解決辦法的能力緊密相連的,這種互操作問題必須得到很好的解決。為了獲得顧客/服務(wù)器的優(yōu)點(diǎn),開發(fā)者必須開發(fā)一組工具,為跨越所有平臺訪問系統(tǒng)資源提供唯一的方法和形式。這使程序員能夠構(gòu)件這樣的應(yīng)用程序:在不同的PC 機(jī)和工作站上所見所

13、感相同,而且無論數(shù)據(jù)在什么位置都使用相同的方法來訪問數(shù)據(jù)。滿足這一要求的最普遍的方法是,在上層應(yīng)用程序和下層通信軟件和操作系統(tǒng)之間使用標(biāo)準(zhǔn)編程接口和協(xié)議。這種標(biāo)準(zhǔn)化的接口和協(xié)議稱為中間件(middleware)。具有了標(biāo)準(zhǔn)的編程接口,在不同的服務(wù)器類型和工作站類型上實(shí)現(xiàn)相同的應(yīng)用就很容易了。這對于用戶來說具有明顯的好處,而廠商也受到市場的驅(qū)動來提供這樣的接口。主要原因是用戶購買應(yīng)用程序而不是服務(wù)器;用戶將只選擇那些運(yùn)行了他們希望的應(yīng)用程序的服務(wù)器。需要標(biāo)準(zhǔn)化的協(xié)議將這些不同的服務(wù)器接口與需要訪問它們的顧客連接起來。目前已經(jīng)有很多中間件軟件包,從非常簡單的到非常復(fù)雜的。它們所具有的共同特點(diǎn)是隱藏

14、不同網(wǎng)絡(luò)協(xié)議和操作系統(tǒng)的復(fù)雜性和不一致性。顧客和服務(wù)器廠商一般都提供了很多非常流行的中間件軟件包供選擇,這樣,用戶可以決定一個特定的中間件策略,然后從各個廠商那里匯集裝置,來支持這個策略。圖4-4給出了在顧客/服務(wù)器結(jié)構(gòu)中中間件的作用。注意,中間件具有顧客端組件和服務(wù)器端組件兩部分,中間件的基本目的是使位于顧客端的應(yīng)用程序或用戶能夠訪問服務(wù)器上的各種服務(wù),同時不需考慮服務(wù)器之間的差別。對于特定的應(yīng)用領(lǐng)域,結(jié)構(gòu)化查詢語言(SQL)提供一種標(biāo)準(zhǔn)化的方式,由本地或遠(yuǎn)程的用戶或應(yīng)用程序訪問關(guān)系數(shù)據(jù)庫。然而關(guān)系數(shù)據(jù)庫廠商盡管支持SQL,但他們將自己專有的擴(kuò)展加到了SQL中。這樣使廠商能夠讓眾多產(chǎn)品有所差

15、別,但也產(chǎn)生了潛在的不兼容性。顧客工作站顧客工作站表示服務(wù)表示服務(wù)服務(wù)器服務(wù)器中間件交互應(yīng)用邏輯中間件交互應(yīng)用邏輯中間件中間件中間件中間件應(yīng)用服務(wù)通信軟件通信軟件應(yīng)用服務(wù)通信軟件通信軟件協(xié)議交互服務(wù)器操作系統(tǒng)顧客操作系統(tǒng)協(xié)議交互服務(wù)器操作系統(tǒng)顧客操作系統(tǒng)硬件平臺硬件平臺硬件平臺硬件平臺圖4-4 在顧客/服務(wù)器結(jié)構(gòu)中中間件的作用圖4-4 在顧客/服務(wù)器結(jié)構(gòu)中中間件的作用4.1.5 文件cache的一致性當(dāng)使用文件服務(wù)器時,文件I/O的性能相對于局部文件訪問具有顯著的下降,主要原因是網(wǎng)絡(luò)帶來的延遲。為了減少這種性能下降,系統(tǒng)可以使用文件高速緩沖器來保存最近訪問的文件記錄。由于局部性原理,使用本地文

16、件高速緩沖器可以減少必須進(jìn)行的遠(yuǎn)程服務(wù)器訪問次數(shù)。文件通道服務(wù)器通道文件通道服務(wù)器通道顧客cache服務(wù)器cache顧客cache服務(wù)器cache磁盤通道磁盤通道磁盤通道磁盤通道顧客磁盤服務(wù)器磁盤顧客磁盤服務(wù)器磁盤圖4-5 文件高速緩存機(jī)制圖4-5 文件高速緩存機(jī)制圖4-5描述了一種典型的文件高速緩存機(jī)制,用于在網(wǎng)絡(luò)互連的工作站組上高速緩存文件。當(dāng)進(jìn)程要進(jìn)行文件訪問時,請求首先提交到進(jìn)程所在的工作站的cache中,如果在那里未得到滿足,則該請求或者傳遞給本地磁盤,或者傳遞給文件服務(wù)器。在服務(wù)器端,首先查詢服務(wù)器上的cache,如果沒有命中,則訪問文件服務(wù)器的磁盤。雙重高速緩存的方法用于減少通信

17、量和磁盤I/O。當(dāng)cache中總能含有遠(yuǎn)程數(shù)據(jù)的精確副本時,這些cache是一致的。Cache之間可能會變得不一致。這是因?yàn)檫h(yuǎn)程數(shù)據(jù)已經(jīng)改變,而相應(yīng)的已經(jīng)陳舊的本地cache副本并沒有被廢棄。當(dāng)一個顧客修改了也被其它顧客高速緩存了的文件時,這種情況就會發(fā)生。這個問題實(shí)際上存在于兩個層次上,如果顧客采用了將任何變化立即寫回服務(wù)器的文件中的策略,則任何具有文件相關(guān)部分的cache副本的其它顧客將具有陳舊的數(shù)據(jù)。如果顧客延遲了將變化寫回服務(wù)器,則問題就更糟了,因?yàn)榉?wù)器本身也只是擁有文件的舊版本,且將請求讀至服務(wù)器的新文件也可能擁有陳舊的數(shù)據(jù)。保持本地cache副本是遠(yuǎn)程數(shù)據(jù)的最新變化的問題就是ca

18、che的一致性問題。解決cache一致性的最簡單的方法是使用文件上鎖技術(shù),以防止多個顧客對文件的同時訪問。這在損害性能和靈活性的前提下保證了一致性。Sprite系統(tǒng)中的機(jī)制提供了更好的方法,任何數(shù)目的遠(yuǎn)程進(jìn)程可以打開一個文件,用于讀入和生成它們自己的顧客cache,但是當(dāng)一個針對服務(wù)器的打開文件請求要求寫入訪問而其它進(jìn)程都是為讀訪問而打開這個文件的,則服務(wù)器要采取兩步行動:第一,它告知寫入進(jìn)程,盡管它保留了一個cache,但是必須在發(fā)生更新時立即寫回所有改變的塊。系統(tǒng)在一個時刻最多只能有一個這樣的顧客。第二,服務(wù)器告知所有使文件打開的讀進(jìn)程,該文件已不再是可緩存的了。4.1.6 服務(wù)員類型在本

19、章所舉的各個例子中都必須指定進(jìn)程的類型(顧客/服務(wù)員)和協(xié)議的類型(面向連接/無連接),而對于服務(wù)員則還要進(jìn)一步指出是并發(fā)型服務(wù)員還是反復(fù)型服務(wù)員(通常顧客并不在乎是和并發(fā)型服務(wù)員還是和反復(fù)型服務(wù)員通信)。這樣,就給出4種可能組合如表4-1。表4-1服務(wù)員類型服務(wù)員類型反復(fù)型并發(fā)型面向連接不常用有代表性無連接有代表性不常用4.2標(biāo)準(zhǔn)Internet服務(wù)和常見的應(yīng)用4.2.1 標(biāo)準(zhǔn)Internet服務(wù)表4-2列出了TCP/IP多數(shù)實(shí)現(xiàn)都提供的一些標(biāo)準(zhǔn)服務(wù)。表中的所有服務(wù)同時使用TCP和UDP提供,并且這兩個協(xié)議的端口號也相同。表4-2 標(biāo)準(zhǔn)TCP/IP服務(wù)名字TCP端口UDP端口RFC說明 Ec

20、ho(回射)77862服務(wù)器返回顧客發(fā)送的數(shù)據(jù)Discard(丟棄)99863服務(wù)器丟棄顧客發(fā)送的數(shù)據(jù)Daytime(時間/日期)1313867服務(wù)器返回可讀的日期和時間Chargen(字符生成)1919864TCP服務(wù)器發(fā)送連續(xù)的字符流,直到顧客終止連接。每當(dāng)顧客發(fā)送一個數(shù)據(jù)報(bào),UDP就返回一個包含隨機(jī)數(shù)量字符的數(shù)據(jù)報(bào)。time(時間)3737868服務(wù)器返回一個32位二進(jìn)制數(shù)值的時間。這個數(shù)值表示從1900年1月1日子時(UTC)以來所流逝的秒數(shù)。這些服務(wù)通常由Unix系統(tǒng)中的inetd守護(hù)進(jìn)程提供。使用標(biāo)準(zhǔn)的telnet顧客程序很容易測試這些功能。這五個功能由inetd內(nèi)部處理的功能,對

21、于TCP版本的echo、discard和chargen服務(wù)器由inetd派生出來后作為子進(jìn)程運(yùn)行,這是因?yàn)樗鼈兌家\(yùn)行到相應(yīng)的顧客終止連接為止。另外兩個TCP服務(wù)器time和daytime并不需要派生,因?yàn)樗鼈兊姆?wù)實(shí)現(xiàn)起來非常簡單(取得當(dāng)前的時間和日期,把它格式化后輸出,在關(guān)閉連接),因此它們由inetd直接處理。所有五個UDP服務(wù)的處理都不需要fork調(diào)用,因?yàn)樗鼈冎痪鸵l(fā)它們的顧客數(shù)據(jù)報(bào)生成并回應(yīng)最多一個數(shù)據(jù)報(bào),因此它們是由inetd直接處理的。4.2.2 常見的Internet應(yīng)用表4-3總結(jié)了各種常見的Internet應(yīng)用程序?qū)f(xié)議的使用情況。表4-3 各種常見的Internet應(yīng)用

22、程序?qū)f(xié)議的使用情況應(yīng)用程序IPICMPUDPTCPPing*Traceroute*OSPF(路由協(xié)議)*RIP(路由協(xié)議)*BGP(路由協(xié)議)*BOOTP(引導(dǎo)協(xié)議)*DHCP(引導(dǎo)協(xié)議)*NTP(時間協(xié)議)*TFTP(簡單的FTP)*SNMP(網(wǎng)絡(luò)管理)*SMTP(電子郵件)*Telnet(虛擬終端)*FTP(文件傳輸)*HTTP(Web)*NNTP(網(wǎng)絡(luò)新聞)*DNS(域名系統(tǒng))*NFS(網(wǎng)絡(luò)文件系統(tǒng))*Sun RPC(遠(yuǎn)程過程調(diào)用)*表中,前兩個應(yīng)用程序Ping和Traceroute是診斷應(yīng)用程序,它們使用ICMP協(xié)議。Traceroute構(gòu)造自己的UDP分組來發(fā)送,并讀ICMP的應(yīng)答

23、。緊接著是三個比較流行的路由協(xié)議,它們展示了路由協(xié)議使用的各種傳輸協(xié)議。OSPF采用原始套接口直接使用IP,而RIP使用UDP,BGB則使用TCP。下面5個是基于UDP的應(yīng)用程序,接著5個應(yīng)用程序使用TCP,最后3個是同時使用UDP和TCP的應(yīng)用程序。4.3 并發(fā)服務(wù)器4.3.1 套接口對一個TCP連接的套接口對(socket pair)是一個定義該連接的兩個端點(diǎn)的四元組:本地IP地址、本地TCP端口號、遠(yuǎn)程IP地址和遠(yuǎn)程TCP端口號。套接口對唯一標(biāo)識一個互連網(wǎng)上的TCP連接。標(biāo)識每個端點(diǎn)的兩個值(IP地址和端口號)通常稱為一個套接口??梢园烟捉涌趯Φ母拍顢U(kuò)展到UDP,即使UDP是面向無連接的

24、。當(dāng)描述套接口函數(shù)(bind、connenct、getpeername等)時,注明它們在說明套接口對中那個值,例如bind函數(shù)要求應(yīng)用程序說明本地IP和本地端口,既可以是TCP套接口,也可以是UDP套接口。4.3.2 并發(fā)服務(wù)器對于像時間/日期這樣簡單的服務(wù)器,使用迭代服務(wù)器(iterative server)具有較好的服務(wù)質(zhì)量;但是,當(dāng)顧客的請求需要長時間服務(wù)時,不可能讓一個服務(wù)器長時間地為一個顧客服務(wù),為了提供網(wǎng)絡(luò)服務(wù)質(zhì)量,而是同時為多個顧客服務(wù)。Unix系統(tǒng)下編寫一個并發(fā)應(yīng)用程序最簡單的方法就是為每個顧客均fork一個子進(jìn)程。下面代碼給出了一個典型的并發(fā)服務(wù)器程序框架。pid_t pid

25、;int listenfd,connfd;listenfd=Socket(); /* create a socket */Bind(listenfd,);Listen(listenfd,LISTENQ); /* listen from the socket */For(;)Connfd=Accept(listenfd,);If(pid=Fork()=0) /* create a child process */Close(listenfd); /* child closes listening socket */Doit(connfd); Close(connfd);Exit(0); /* c

26、hild terminates */Close(connfd); /* parent closes connected socket */并發(fā)服務(wù)器中主服務(wù)器循環(huán)派生子進(jìn)程來處理每個新的連接。并發(fā)服務(wù)器讓派生的子進(jìn)程來處理顧客的請求。具體過程如圖4-6所示。(監(jiān)聽套接口)*.21.*.*(監(jiān)聽套接口)*.21.*.*請求(1)請求(1)服務(wù)器服務(wù)器顧客顧客Fork(2)Fork(2)服務(wù)器(子進(jìn)程)服務(wù)器(子進(jìn)程),1300,21,1300,21連接(3), 21,1300, 21,1300(已連接套接口)圖4-6 并發(fā)服務(wù)器讓子進(jìn)程處理顧客請求的服務(wù)圖中有一個服務(wù)器,它的IP地址為。服務(wù)器在

27、它的眾所周知的端口(例如21端口)上執(zhí)行被動打開,并等待顧客的請求。這里使用符號*.21.*.*指出服務(wù)器的套接口對。服務(wù)器在任意本地接口(第一個星號)的端口21上等待連接請求。遠(yuǎn)程IP地址和遠(yuǎn)程端口沒有指定,用“*.*”表示。這里的星號稱為通配(wildcard)符。如果運(yùn)行服務(wù)器的主機(jī)有多個IP地址,服務(wù)器可以說明它只接受到達(dá)某個特定本地接口的外來連接。這是指定一個接口或者任意接口的選擇。服務(wù)器不能指定多個地址的列表。通配的本地地址表示“任意”接口。此時,必須區(qū)別服務(wù)器的監(jiān)聽套接口和已連接套接口。這里,已連接套接口使用和監(jiān)聽套接口相同的端口號:21。同時,一旦建立連接,以連接的本地套接口的

28、本地地址()隨即填入。如果下一個顧客(假設(shè)IP地址為23,端口號為1301)隨即也提出了服務(wù)請求,服務(wù)器就再派生第二個子進(jìn)程對它進(jìn)行服務(wù),這時建立連接的四元組為, 21,23,1301。服務(wù)器能夠區(qū)別這兩個連接:第一個連接的套接口對和第二個連接的套接口對是不同的。通過上面的例子可以看出,TCP無法僅僅通過查看目的端口來分離外來的分組。它必須查看套接口對的所有四個元素才能確定由哪個端點(diǎn)接收到達(dá)的分組。對于上面的例子,對于端口21存在三個套接口,如果一個分組來自端口1300,目的地為端口 21,那么它就傳送給第一個子進(jìn)程;如果一個分組來自23端口1301,目的地為端口 21,那么它就傳送給第二個子

29、進(jìn)程;所有其它的目的端口21的TCO分組則傳送給擁有監(jiān)聽套接口的初始服務(wù)器(父進(jìn)程)。4.3.3 緩沖區(qū)大小及其限制由于通信雙方及中間節(jié)點(diǎn)的配置不同,有些會影響應(yīng)用程序數(shù)據(jù)的傳輸。影響IP數(shù)據(jù)報(bào)大小的主要限制有:IPv4數(shù)據(jù)報(bào)的最大值為65535字節(jié),包括IPv4的頭部,總長度字段占16位。IPv6數(shù)據(jù)報(bào)的最大值為65575字節(jié),包括40字節(jié)的IPv6頭部,有效負(fù)載長度字段占16位。這里IPv6的有效負(fù)載長度字段不含IPv6頭部,而IPv4的總長度字段包含IPv4頭部。另外,IPv6有一個特大有效負(fù)載選項(xiàng),它把有效負(fù)載長度字段擴(kuò)展到32位,但是這個選項(xiàng)要求MTU超過65535的數(shù)據(jù)鏈路,這個選

30、項(xiàng)是為主機(jī)到主機(jī)的內(nèi)部連接而設(shè)計(jì)的,例如HIPPI,它們沒有內(nèi)在的MTU。很多網(wǎng)絡(luò)有一個最大傳輸單元MTU,它由硬件規(guī)定。例如以太網(wǎng)的MTU為1500字節(jié)。其它鏈路其MTU可以配置。IPv4要求的最小MTU是68字節(jié),IPv6要求的最小MTU為576字節(jié)。在兩臺主機(jī)間的路徑上的最小MTU稱為路徑MTU。1500字節(jié)的以太網(wǎng)MTU是當(dāng)今常見的路徑MTU。路徑MTU在不同方向可以不相同,因?yàn)樵谝蛱鼐W(wǎng)中路由是非對稱的。當(dāng)一個數(shù)據(jù)報(bào)將從某個接口發(fā)出時,如果它的大小超過相應(yīng)鏈路的MTU,IPv4和IPV6都將執(zhí)行分片(fragmentation)操作。各片段到達(dá)目的地前不會被重組(reassemblin

31、g)。IPV4主機(jī)對其產(chǎn)生的數(shù)據(jù)報(bào)執(zhí)行分片,IPV4路由器對其轉(zhuǎn)發(fā)的數(shù)據(jù)報(bào)也執(zhí)行分片。但是,IPv6只在數(shù)據(jù)報(bào)產(chǎn)生的主機(jī)執(zhí)行分片;IPv6路由器對其轉(zhuǎn)發(fā)的數(shù)據(jù)報(bào)不進(jìn)行分片。事實(shí)上,IPv6路由器可以執(zhí)行分片,但只對那些由路由器產(chǎn)生的數(shù)據(jù)報(bào)而不是轉(zhuǎn)發(fā)的數(shù)據(jù)報(bào)。這時的路由器實(shí)際上作為主機(jī)運(yùn)行。例如,大多數(shù)路由器支持Telnet協(xié)議,系統(tǒng)管理員就用它來配置路由器。由路由器的Telnet服務(wù)器產(chǎn)生的IP數(shù)據(jù)報(bào)是由路由器產(chǎn)生的,而不是路由器轉(zhuǎn)發(fā)的。IPv4頭部的DF(“不分片”)位若被設(shè)置,那么不管是發(fā)送主機(jī)還是轉(zhuǎn)發(fā)路由器都不能對本數(shù)據(jù)報(bào)分片。當(dāng)路由器接收到一個超過其外出鏈路MTU大小且設(shè)置了DF位的I

32、Pv4數(shù)據(jù)報(bào)時,它將產(chǎn)生一個ICMP的“destination unreachable, fragmentation needed but DF bit set(目的地不可達(dá),需要分片但DF位已設(shè)置)”出錯消息。由于IPv6路由器不執(zhí)行分片,因此IPv6數(shù)據(jù)報(bào)隱含設(shè)置了DF位。如果IPv6路由器接收到一個超過其外出鏈路MTU大小的IPv6數(shù)據(jù)報(bào)年,它將產(chǎn)生一個ICMPv6的“packet too big(分組太大)”的出錯消息。IPv4的DF位和IPv6的隱含DF位可用于路徑MTU的發(fā)現(xiàn)。例如,如果TCP使用IPv4技術(shù),它發(fā)送的數(shù)據(jù)報(bào)都將設(shè)置DF位。如果某個中間路由器返回一個ICMP的“de

33、stination unreachable, fragmentation needed but DF bit set“錯誤,TCP就減少每個數(shù)據(jù)報(bào)的數(shù)據(jù)量并重傳。路徑MTU的發(fā)現(xiàn)對IPv4是可選的,但所有IPv6的實(shí)現(xiàn)都必須支持它。IPv4和IPv6都定義了最小重組緩沖區(qū)大?。喝魏蜪Pv4和IPv6的實(shí)現(xiàn)都必須支持的最小數(shù)據(jù)報(bào)大小。對IPv4和其值為576字節(jié),對IPv6為1500字節(jié)。例如,對IPv4來說,如果不能確信給定的目的主機(jī)是否能接收577字節(jié)的數(shù)據(jù)報(bào)。所以很多使用UDP的應(yīng)用程序(DNS、RIP、TFTP、BOOTP、SNMP)避免產(chǎn)生大于576字節(jié)的數(shù)據(jù)報(bào)。TCP有一個MSS(最

34、大分片大?。?,用于向?qū)Ψ絋CP通告在每個分片中能發(fā)送的最大TCP 數(shù)據(jù)量, 使用MSS的目的是告訴對方其重組緩沖區(qū)的實(shí)際值,從而避免分片。MSS經(jīng)常設(shè)置成MTU減去IP和TCP頭部的固定長度。在以太網(wǎng)環(huán)境下IPv4的MSS為1460字節(jié),使用IPv6的MSS值為1440字節(jié)(兩者的TCP頭部都為20字節(jié),而IPv4頭部是20字節(jié),IPv6的頭部是40字節(jié))。在TCP的MSS選項(xiàng)中,MSS值是一個16位字段,最大值是65535字節(jié)。這個值適合IPv4,因?yàn)镮Pv4數(shù)據(jù)報(bào)中的最大TCP數(shù)據(jù)量為65495字節(jié)(即65535減去IPv4頭部20字節(jié)和TCP頭部20字節(jié))。但是,IPv6有特大有效負(fù)荷選

35、項(xiàng),因此需要使用另外的技術(shù)。首先,沒有特大有效負(fù)荷選項(xiàng)的IPv6數(shù)據(jù)報(bào)中最大的TCP數(shù)據(jù)量為65515字節(jié)(即65535減去TCP頭部20字節(jié))。因此65535這個MSS值被認(rèn)為是“無限”的特殊值,它只在用到特大有效負(fù)荷選項(xiàng)時才有用,而這種情況又要求MTU超過65535。如果TCP使用特大有效負(fù)荷選項(xiàng),并且接收到的對方通告的MSS超過65535,那么它所發(fā)送數(shù)據(jù)報(bào)的大小限制就是接口MTU。如果這個值太大(即路徑上某個鏈路的MTU比它?。?,那么路徑MTU的發(fā)現(xiàn)功能將確定這個最小值。4.3.4 TCP發(fā)送圖4-7說明了應(yīng)用程序發(fā)送數(shù)據(jù)到TCP套接口的過程。用戶進(jìn)程應(yīng)用進(jìn)程緩沖區(qū)(大小任意)應(yīng)用進(jìn)程

36、用戶進(jìn)程應(yīng)用進(jìn)程緩沖區(qū)(大小任意)應(yīng)用進(jìn)程內(nèi)核套接口發(fā)送緩沖區(qū)內(nèi)核套接口發(fā)送緩沖區(qū)TCPTCPMSS大小的TCP分片MSSMTU-40(IPv4)或-60(IPv6)MSS大小的TCP分片MSSMTU-40(IPv4)或-60(IPv6)IPIPMTU大小的IPv4或IPv6分組MTU大小的IPv4或IPv6分組輸出隊(duì)列輸出隊(duì)列數(shù)據(jù)鏈路數(shù)據(jù)鏈路圖4-7 應(yīng)用程序發(fā)送數(shù)據(jù)到TCP套接口的過程圖4-7 應(yīng)用程序發(fā)送數(shù)據(jù)到TCP套接口的過程每個TCP套接口都有一個發(fā)送緩沖區(qū),用戶可以使用SO_SNDBUF套接口選項(xiàng)來改變這個緩沖區(qū)的大小。當(dāng)應(yīng)用程序調(diào)用write時,內(nèi)核從應(yīng)用進(jìn)程的緩沖區(qū)中拷貝所有數(shù)

37、據(jù)到套接口的發(fā)送緩沖區(qū)。如果套接口的發(fā)送緩沖區(qū)不能存放應(yīng)用程序的所有數(shù)據(jù)(即應(yīng)用程序的緩沖區(qū)大于套接口發(fā)送緩沖區(qū),或者套接口發(fā)送緩沖區(qū)還有其它數(shù)據(jù)),應(yīng)用程序?qū)⒈粧炱穑ㄋ撸@里假設(shè)套接口是阻塞的(缺省設(shè)置)。內(nèi)核將不從write系統(tǒng)調(diào)用返回,直到應(yīng)用進(jìn)程緩沖區(qū)中的所有數(shù)據(jù)都拷貝到套接口發(fā)送緩沖區(qū)。所以從寫一個TCP套接口的write調(diào)用成功返回僅表示可以重新使用應(yīng)用進(jìn)程的緩沖區(qū)。它并不能告訴用戶對方的TCP或?qū)Ψ綉?yīng)用進(jìn)程已接收到數(shù)據(jù)。TCP取出套接口發(fā)送緩沖區(qū)的數(shù)據(jù)并把它發(fā)送給對方TCP,其過程基于TCP數(shù)據(jù)傳送的所有規(guī)則。對方TCP必須確認(rèn)收到的數(shù)據(jù),只有收到對方的ACK,發(fā)送方TCP才

38、能刪除套接口發(fā)送緩沖區(qū)中已確認(rèn)的數(shù)據(jù)。TCP必須保留數(shù)據(jù)拷貝直到對方確認(rèn)為止。TCP以MSS大小或者更小的塊發(fā)送數(shù)據(jù)給IP(它同時給每個數(shù)據(jù)塊填上TCP頭部以構(gòu)成分片),其中MSS是由對方通告的,當(dāng)對方未通告時使用536這個值。IP給每個TCP分片填上IP頭部以構(gòu)成數(shù)據(jù)報(bào),查找其目的IP地址的路由表項(xiàng)以確定外出接口,然后把數(shù)據(jù)報(bào)傳遞給相應(yīng)的數(shù)據(jù)鏈路。IP可能先將數(shù)據(jù)報(bào)分段,再傳送給鏈路層。但如上所述,MSS選項(xiàng)的目的是避免分片,而新的實(shí)現(xiàn)又使用路徑MTU發(fā)現(xiàn)功能。每個鏈路有一個輸出隊(duì)列,如果輸出隊(duì)列滿,則分組丟棄,并沿協(xié)議棧向上返回一個錯誤。TCP將注意這個錯誤,并在以后的某個時刻重傳這個分片

39、,但應(yīng)用進(jìn)程不知道這些細(xì)節(jié)。4.3.5 UDP發(fā)送圖4-8說明了應(yīng)用程序發(fā)送數(shù)據(jù)到UDP套接口的過程。用戶進(jìn)程應(yīng)用進(jìn)程緩沖區(qū)應(yīng)用進(jìn)程用戶進(jìn)程應(yīng)用進(jìn)程緩沖區(qū)應(yīng)用進(jìn)程內(nèi)核套接口發(fā)送緩沖區(qū)內(nèi)核套接口發(fā)送緩沖區(qū)UDPUDPUDP數(shù)據(jù)報(bào) UDP數(shù)據(jù)報(bào) IPIPMTU大小的IPv4或IPv6分組MTU大小的IPv4或IPv6分組輸出隊(duì)列輸出隊(duì)列數(shù)據(jù)鏈路數(shù)據(jù)鏈路圖4-8 應(yīng)用程序發(fā)送數(shù)據(jù)到UDP套接口的過程圖4-8 應(yīng)用程序發(fā)送數(shù)據(jù)到UDP套接口的過程在圖4-8中,套接口發(fā)送緩沖區(qū)用虛線框,因?yàn)樗⒉淮嬖凇DP套接口有發(fā)送緩沖區(qū)的大?。ㄓ脩艨梢允褂肧O_SNDBUF套接口選項(xiàng)修改),但是它僅僅是發(fā)送(se

40、ndto)到套接口的UDP數(shù)據(jù)報(bào)的上限。如果應(yīng)用程序發(fā)送一個大于套接口發(fā)送緩沖區(qū)的數(shù)據(jù)報(bào),則返回EMSGSIZE錯誤。由于UDP是一種不可靠的服務(wù),它不必保存應(yīng)用程序的數(shù)據(jù)拷貝,因此不需要一個真正的緩沖區(qū)。(應(yīng)用進(jìn)程的數(shù)據(jù)沿協(xié)議棧向下傳遞時,以某種形式拷貝到內(nèi)核的緩沖區(qū),當(dāng)鏈路層把數(shù)據(jù)傳出后這個拷貝將丟棄。)UDP簡單地填加它的8個字節(jié)的頭部以構(gòu)成數(shù)據(jù)報(bào)并把它傳遞給IP。IPv4或IPv6給它填加相應(yīng)的IP頭部,執(zhí)行路由操作確定外出接口,然后或者直接將數(shù)據(jù)報(bào)加入鏈路層輸出隊(duì)列(如果適合于MTU),或者分段后在把每個段加入數(shù)據(jù)鏈路層的輸出隊(duì)列。如果UDP應(yīng)用進(jìn)程發(fā)送一個大的數(shù)據(jù)報(bào)(例如2000字

41、節(jié)數(shù)據(jù)報(bào)),它比TCP應(yīng)用進(jìn)程更有可能分片,因?yàn)門CP會將應(yīng)用進(jìn)程數(shù)據(jù)分成MSS大小的塊,但UDP卻沒有這個能力。從寫UDP套接口的sendto調(diào)用成功返回表示數(shù)據(jù)報(bào)或所有片段已被加入鏈路層的輸出隊(duì)列。如果輸出隊(duì)列沒有足夠的空間存放數(shù)據(jù)報(bào)或它的某個分片,UDP將返回應(yīng)用進(jìn)程ENOBUFS錯誤。這里需要注意的是,有些UDP的實(shí)現(xiàn)不返回這種錯誤,這樣甚至數(shù)據(jù)報(bào)未經(jīng)發(fā)出就丟失的情況應(yīng)用進(jìn)程也不知道。4.4 網(wǎng)絡(luò)服務(wù)員工作模式當(dāng)用戶開發(fā)一個服務(wù)器程序時,有如下類型的進(jìn)程控制方法可供選擇:迭代服務(wù)器程序。這種方式主要用于簡單的網(wǎng)絡(luò)服務(wù)。它的主要缺點(diǎn)是在當(dāng)前顧客服務(wù)完成之前,新到達(dá)的顧客無法得到服務(wù)。并發(fā)

42、服務(wù)器程序,它為每個顧客fork一個子進(jìn)程提供服務(wù),這是Unix服務(wù)器程序通常的做法。使用select調(diào)用在一個進(jìn)程內(nèi)同時服務(wù)多個顧客的TCP服務(wù)器程序。使用線程替代進(jìn)程實(shí)現(xiàn)的并發(fā)服務(wù)器程序。本節(jié)中介紹兩種新的并發(fā)程序設(shè)計(jì)方法:預(yù)先派生子進(jìn)程(preforking)。服務(wù)器啟動后就派生一組子進(jìn)程,形成一個子進(jìn)程池。沒當(dāng)?shù)絹硪粋€顧客請求,就從進(jìn)程池內(nèi)選擇一個可用子進(jìn)程為它服務(wù)。預(yù)先創(chuàng)建線程(prethreading)。服務(wù)器啟動后就創(chuàng)建一組線程,形成一個線程池。每個顧客請求由池中的一個線程提供服務(wù)。4.4.1 TCP迭代服務(wù)器程序迭代服務(wù)器總是在完全處理了一個顧客的請求后,才響應(yīng)下一個顧客的請求

43、。這種方式主要用于簡單的網(wǎng)絡(luò)服務(wù),下面程序給出了使用迭代方法實(shí)現(xiàn)的一個簡單的時間/日期服務(wù)器程序。#includeunp.h#includeintmain(int argc, char *argv)intlistenfd, connfd;struct sockaddr_inservaddr;charbuffMAXLINE;time_tticks;listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr);servaddr.sin_family = AF_INET;servaddr.sin_addr.s

44、_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(13);/* daytime server */Bind(listenfd, (SA *) &servaddr, sizeof(servaddr);Listen(listenfd, LISTENQ);for ( ; ; ) connfd = Accept(listenfd, (SA *) NULL, NULL); ticks = time(NULL); snprintf(buff, sizeof(buff), %.24srn, ctime(&ticks); Write(connfd, buf

45、f, strlen(buff);Close(connfd);從進(jìn)程控制的角度來看,迭代服務(wù)器是最快的,因?yàn)樗贿M(jìn)行進(jìn)程控制。4.4.2 TCP并發(fā)服務(wù)器程序傳統(tǒng)上,并發(fā)服務(wù)器是調(diào)用fork派生一個子進(jìn)程來處理顧客的請求。這使得服務(wù)器可在同一時間為多個顧客提供服務(wù)。唯一的限制是操作系統(tǒng)對同一用戶可擁有的進(jìn)程數(shù)量的限制。下面的程序例子是一個并發(fā)服務(wù)器的實(shí)現(xiàn)。絕大多數(shù)TCP服務(wù)器程序也是這樣編寫的。#includeunp.hintmain(int argc, char *argv)intlistenfd, connfd;pid_tchildpid;voidsig_chld(int), sig_int

46、(int), web_child(int);socklen_tclilen, addrlen;struct sockaddr*cliaddr;if (argc = 2)listenfd = Tcp_listen(NULL, argv1, &addrlen);else if (argc = 3)listenfd = Tcp_listen(argv1, argv2, &addrlen);elseerr_quit(usage: serv01 );cliaddr = Malloc(addrlen);Signal(SIGCHLD, sig_chld);Signal(SIGINT, sig_int);fo

47、r ( ; ; ) clilen = addrlen;if ( (connfd = accept(listenfd, cliaddr, &clilen) 0) if (errno = EINTR)continue;/* back to for() */elseerr_sys(accept error);if ( (childpid = Fork() = 0) /* child process */Close(listenfd);/* close listening socket */web_child(connfd);/* process the request */exit(0);Close

48、(connfd);/* parent closes connected socket */* end serv01 */并發(fā)服務(wù)器的問題在于fork子進(jìn)程時所消耗的CPU時間。20世紀(jì)80年代后期,當(dāng)一個服務(wù)器一天只需處理幾百、幾千個顧客請求時,這樣實(shí)現(xiàn)從性能上是能夠滿足的。然而到了Web時代,一個重負(fù)荷的Web服務(wù)器一天的訪問數(shù)量以百萬計(jì)。這種情況下,就單臺主機(jī)而言,對于最繁忙的站點(diǎn)往往運(yùn)行多臺主機(jī)來分?jǐn)傌?fù)載。改進(jìn)服務(wù)器性能的方法有以下幾種??梢圆捎妙A(yù)先派生子進(jìn)程技術(shù)來提高并發(fā)服務(wù)器的性能。預(yù)先派生子進(jìn)程服務(wù)器程序不再為每個顧客請求fork一個子進(jìn)程,而是在服務(wù)器啟動時就預(yù)先派生一組子進(jìn)程,

49、做好為接入的顧客請求服務(wù)的準(zhǔn)備。圖4-9顯示了一個預(yù)先派生N個子進(jìn)程的服務(wù)器正在為2個顧客同時服務(wù)的情形。顧客1子進(jìn)程1顧客1子進(jìn)程1顧客2子進(jìn)程2顧客2子進(jìn)程2父進(jìn)程父進(jìn)程子進(jìn)程3子進(jìn)程3可用子進(jìn)程池可用子進(jìn)程池.子進(jìn)程N(yùn)子進(jìn)程N(yùn)圖4-9 預(yù)先派生子進(jìn)程的并發(fā)服務(wù)器圖4-9 預(yù)先派生子進(jìn)程的并發(fā)服務(wù)器使用預(yù)先派生子進(jìn)程的描述代碼如下:#includeunp.hstatic intnchildren;static pid_t*pids;intmain(int argc, char *argv)intlistenfd, i;socklen_taddrlen;voidsig_int(int);pi

50、d_tchild_make(int, int, int);if (argc = 3)listenfd = Tcp_listen(NULL, argv1, &addrlen);else if (argc = 4)listenfd = Tcp_listen(argv1, argv2, &addrlen);elseerr_quit(usage: serv02 );nchildren = atoi(argvargc-1);pids = Calloc(nchildren, sizeof(pid_t);for (i = 0; i nchildren; i+)pidsi = child_make(i, li

51、stenfd, addrlen);/* parent returns */Signal(SIGINT, sig_int);for ( ; ; )pause();/* everything done by children */這種技術(shù)的優(yōu)點(diǎn)在于:不需要引入父進(jìn)程執(zhí)行fork的開銷,新的顧客請求就能得到服務(wù)。而缺點(diǎn)在于:每次啟動服務(wù)器時,父進(jìn)程必須確定需要產(chǎn)生多少個子進(jìn)程。如果不考慮再派生子進(jìn)程,一旦所有子進(jìn)程都被顧客請求占用,此時新到的請求將被暫時忽略,直到有一個子進(jìn)程可用。對于父進(jìn)程可以監(jiān)視可用子進(jìn)程數(shù),一旦低于某個系統(tǒng)預(yù)先設(shè)定的閥值就再派生額外的子進(jìn)程。同樣,如果空閑子進(jìn)程數(shù)大于某個閥值,

52、則父進(jìn)程將終止部分新派生的子進(jìn)程。因?yàn)檫^多的子進(jìn)程會占用系統(tǒng)的資源,從而導(dǎo)致系統(tǒng)性能下降。當(dāng)系統(tǒng)負(fù)載較輕時,傳統(tǒng)的并發(fā)服務(wù)器模型能夠很好地處理顧客的請求,也就是每來一個請求,服務(wù)器就派生一個子進(jìn)程為之服務(wù)。它甚至可以和inetd結(jié)合使用,由inetd負(fù)責(zé)接收每個連接。對于重負(fù)載情況,例如web服務(wù)器,可以使用相關(guān)的技術(shù)增強(qiáng)服務(wù)器的處理能力。4.4.3 4.4BSD上的實(shí)現(xiàn)在源自Berkeley的內(nèi)核實(shí)現(xiàn)上,父進(jìn)程在派生子進(jìn)程之前創(chuàng)建監(jiān)聽套接口,而每次fork子進(jìn)程時,各個子進(jìn)程復(fù)制父進(jìn)程的全部描述字。圖4-10描述了proc結(jié)構(gòu)(每個進(jìn)程一個)、監(jiān)聽描述字的單個file結(jié)構(gòu)以及單個socket

53、結(jié)構(gòu)的關(guān)系。在proc結(jié)構(gòu)中,描述字只是某個數(shù)組的一個下標(biāo),用于引用一個file結(jié)構(gòu)。而fork派生子進(jìn)程時,子進(jìn)程復(fù)制描述字的特性之一就是:子進(jìn)程中給定的描述字所引用的file結(jié)構(gòu)與父進(jìn)程中同一描述字所引用的file結(jié)構(gòu)一致。每個file結(jié)構(gòu)有一個訪問計(jì)數(shù),它在文件或者套接口打開時為1,而每當(dāng)調(diào)用fork或者dup本描述字時,它就增加1。在具有N個子進(jìn)程的例子中,file結(jié)構(gòu)的訪問計(jì)數(shù)為N+1(父進(jìn)程雖然從不調(diào)用accept,但它并未關(guān)閉該監(jiān)聽描述字)。當(dāng)程序啟動后,N個子進(jìn)程被派生,它們分別調(diào)用accept并由內(nèi)核置入睡眠狀態(tài)。當(dāng)?shù)谝粋€顧客連接到來時,N個睡眠進(jìn)程均被喚醒。這是由于這N個進(jìn)

54、程共享一個socket結(jié)構(gòu),導(dǎo)致它們睡眠在同一等待通道(wait channel),即socket結(jié)構(gòu)的so_timeo成員上。但是,雖然N個進(jìn)程同時喚醒,只有最先被調(diào)度的進(jìn)程才能獲得顧客連接,而其它N-1個進(jìn)程在執(zhí)行過程中,它們會發(fā)現(xiàn)隊(duì)列長度為0(連接已被取走),因此被再次投入睡眠。這通常被稱為驚群(thundering herd)問題,因?yàn)楸M管只有一個進(jìn)程可以獲得連接,但所有進(jìn)程都被喚醒。這樣雖然可以工作,但這種情況會導(dǎo)致系統(tǒng)性能的下降。為了避免驚群問題的發(fā)生,用戶不希望有額外子進(jìn)程空閑,某些Unix內(nèi)核有一個名字為wakeup_one的函數(shù),對于等待某個事件的一群進(jìn)程,它只喚醒一個等待進(jìn)

55、程,而不是所有進(jìn)程。但是BSD操作系統(tǒng)內(nèi)核沒有提供這個函數(shù)。procprocprocprocprocproc子進(jìn)程N(yùn)listenfd子進(jìn)程1子進(jìn)程N(yùn)listenfd子進(jìn)程1listenfd父進(jìn)程listenfd.filefilesocketsocket圖4-10 proc、file和socket結(jié)構(gòu)的關(guān)系圖4-10 proc、file和socket結(jié)構(gòu)的關(guān)系4.5 守護(hù)進(jìn)程4.5.1 守護(hù)進(jìn)程的原理守護(hù)進(jìn)程(daemon)是在系統(tǒng)后臺運(yùn)行不受終端控制的進(jìn)程,只要系統(tǒng)沒有關(guān)機(jī)或者崩潰,守護(hù)進(jìn)程將在系統(tǒng)中不間斷地運(yùn)行。Unix系統(tǒng)中一般有很多守護(hù)進(jìn)程(使用ps ax命令可以看出)在后臺運(yùn)行(20到

56、50個),執(zhí)行不同的系統(tǒng)任務(wù)。為了保證守護(hù)進(jìn)程正常地工作,必須使守護(hù)進(jìn)程和其它進(jìn)程運(yùn)行的環(huán)境隔離開,避免由于其它進(jìn)程的行為影響守護(hù)進(jìn)程的工作。守護(hù)進(jìn)程要脫離所有的終端的原因是因?yàn)槭刈o(hù)進(jìn)程可能是從終端上啟動(與從初始化腳本中啟動相反),在這之后這個終端可能執(zhí)行其它的任務(wù)。例如,如果在某個終端上啟動了一個守護(hù)進(jìn)程后從該終端上注銷,其它用戶又從該終端登錄,那么任何關(guān)于守護(hù)進(jìn)程的錯誤信息不應(yīng)在后面用戶的終端會話過程中出現(xiàn)。同樣,由終端上的一些鍵(熱鍵)所產(chǎn)生的信號(中斷信號),不應(yīng)對以前從該終端上啟動的任何守護(hù)進(jìn)程造成影響。雖然使服務(wù)員程序在系統(tǒng)后臺運(yùn)行很容易,但是用戶還應(yīng)該使程序能自動轉(zhuǎn)到后臺運(yùn)行并

57、且脫離與終端的聯(lián)系。啟動守護(hù)進(jìn)程的方法主要有:在系統(tǒng)啟動時很多守護(hù)程序是由系統(tǒng)初始化腳本啟動。這些腳本一般在/etc目錄或者以/etc/rc開頭的目錄下,它們的位置和內(nèi)容依賴于具體的實(shí)現(xiàn)。由這些腳本啟動的守護(hù)進(jìn)程在開始時擁有超級用戶權(quán)限。例如,syslog守護(hù)進(jìn)程、inetd守護(hù)進(jìn)程、Web服務(wù)員守護(hù)進(jìn)程等等。許多網(wǎng)絡(luò)服務(wù)員是由inetd超級服務(wù)員啟動的。inetd自身是由上一步中的某個腳本啟動的。Inetd監(jiān)聽所有的網(wǎng)絡(luò)請求,當(dāng)請求到來時根據(jù)請求的類型啟動實(shí)際的服務(wù)員(例如,收到一個FTP請求,inetd就啟動一個FTP服務(wù)員)。 cron守護(hù)進(jìn)程按規(guī)則定期執(zhí)行一些程序,由它啟動的程序也以守

58、護(hù)進(jìn)程的方式運(yùn)行。cron自身是在系統(tǒng)啟動過程中由第一步啟動的??梢杂胊t命令指定在將來的某個時刻執(zhí)行程序。at守護(hù)進(jìn)程在到達(dá)相應(yīng)的時間時會啟動程序,被啟動的程序以守護(hù)進(jìn)程的方式運(yùn)行。不管是前臺還是后臺,守護(hù)進(jìn)程也可以在終端上啟動,這在調(diào)試守護(hù)進(jìn)程或守護(hù)進(jìn)程由于某種原因終止而需要重新啟動時經(jīng)常使用。由于守護(hù)進(jìn)程沒有控制終端,在發(fā)生問題時它要用一些其它方式以輸出消息。這些消息既有一般的通告消息,也有需要管理員處理的緊急事件消息。syslog函數(shù)是輸出這些消息的標(biāo)準(zhǔn)方式,它將消息發(fā)往syslog守護(hù)進(jìn)程。4.5.2 syslog守護(hù)進(jìn)程Unix或Linux系統(tǒng)通常會從一個初始化腳本中啟動syslo

59、g守護(hù)進(jìn)程,只要系統(tǒng)運(yùn)行,它就一直運(yùn)行。源自Berkeley的syslog守護(hù)進(jìn)程的實(shí)現(xiàn)在啟動時執(zhí)行以下操作:讀入配置文件,通常配置文件是/etc/syslog.conf。它設(shè)定守護(hù)進(jìn)程對接收每次鍵入的各種登記消息(log message)怎樣處理。這些消息可能被寫入一個文件(一種特殊文件是/dev/console,將包消息寫到控制臺上),或發(fā)給指定的用戶(如果該用戶已經(jīng)登錄到系統(tǒng)),或轉(zhuǎn)發(fā)給另一個主機(jī)上的syslog守護(hù)進(jìn)程。創(chuàng)建一個Unix域套接口,給它捆綁路徑名/var/run/log(有些系統(tǒng)為/dev/log)。創(chuàng)建一個UDP套接口,給它捆綁端口號為514(syslog服務(wù)使用的端口

60、號)。打開路徑名/dev/klog,內(nèi)核中的所有出錯消息作為這個設(shè)備的輸入出現(xiàn)。完成上述工作后,syslog守護(hù)進(jìn)程運(yùn)行一個無限循環(huán),循環(huán)中調(diào)用select等待三個描述字(以上第2、3、4步產(chǎn)生的描述字)之一變?yōu)榭勺x,讀入登記消息,并按配置文件對消息進(jìn)行處理。如果該守護(hù)進(jìn)程收到SIGHUP信號,它將重新讀入配置文件。通過建立一個Unix域數(shù)據(jù)報(bào)套接口,并向syslog守護(hù)進(jìn)程綁定的路徑名發(fā)送消息,用戶就能從自己的守護(hù)進(jìn)程向syslog守護(hù)進(jìn)程發(fā)送登記消息,但更簡單的接口是使用syslog函數(shù)。另外也可以創(chuàng)建一個UDP套接口,將日志消息發(fā)到回饋地址及端口514。對于syslog守護(hù)進(jìn)程,新的實(shí)現(xià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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論