蔡坤琪,趙安學,邢潔清*
(1.瓊臺師范學院 信息科學技術學院,海南 ???571100;2.瓊臺師范學院 教育大數(shù)據(jù)與人工智能研究所,海南 ???571100)
在計算機網(wǎng)絡中,網(wǎng)絡主機除了要給本地用戶提供服務,還要給網(wǎng)絡的其他主機的用戶提供服務。為遠程計算機提供服務的進程被稱為Server進程,本地計算機請求服務并發(fā)起本次進程通信的進程被稱為Client進程。當客戶端進程發(fā)出服務請求時,遠程服務器進程會響應該客戶端請求,并提供進程間通信的一種模式,被稱為客戶端/服務器模式。
在TCP/IP網(wǎng)絡應用中,通信的兩個進程間相互作用的主要模式是客戶機/服務器模式(Client/Server),采用Client/ Server模式的理由主要有以下幾點。
互聯(lián)網(wǎng)資源分布具有不均勻性。
2.1.1 硬件
網(wǎng)絡中主機系統(tǒng)類型的作用和能力等各方面差異很大。主機設備可以是某臺大型的電腦高配置的服務器,也可以是一臺個人電腦,甚至是一個PDA或是一個家電。
2.1.2 軟件
由于所屬權管理與運行環(huán)境等方面的原因,應用軟件都是安裝在客戶端主機系統(tǒng)中,用戶可以訪問網(wǎng)絡,注冊成合法用戶,然后提出和完成計算任務。
在互聯(lián)網(wǎng)環(huán)境中,進程通信具有異步性。不同結(jié)點分布在不同網(wǎng)絡空間,結(jié)點系統(tǒng)中的進程不時發(fā)出通信請求,希望和某臺主機的某個進程通信。
該模式不存在統(tǒng)一調(diào)度與協(xié)調(diào)的高層操作系統(tǒng)。
Client/ Server模式的工作實質(zhì)是“請求驅(qū)動”。毎次通信由Client進程隨機發(fā)起。
在互聯(lián)網(wǎng)中,Server必須要有處理并發(fā)請求的能力。在同一個時點,可能有多個Client進程向一個Server發(fā)出服務請求。
解決服務器處理并發(fā)請求的方案基本上有以下兩種:一是采用并發(fā)服務器的方法;二是采用重復服務器的方法。
服務器并發(fā)的核心是服務器的守護程序(Daemon),系統(tǒng)啟動的時候隨之啟動。在沒有Client的服務請求到達時,并發(fā)Server處于等待狀態(tài)。
當客戶端服務請求到達時,服務器端根據(jù)客戶端的服務請求的進程激活相應的子進程,該子進程為客戶端提供服務,服務器返回等待狀態(tài)。
服務器必須具有在整個網(wǎng)絡中眾所周知的進程地址。互聯(lián)網(wǎng)中的Client進程可以根據(jù)Server進程的熟知地址,向Server提出服務請求。在實現(xiàn)進程通信的過程中,Client與 Server進程分別形成自己的半相關的三元組,然后Client根據(jù)Server進程的熟知進程地址建立相關的五元組。
重復服務器通過設置請求隊列來存儲客戶端的服務請求。服務器采用先到先得的原則,依次處理客戶的服務請求。
并發(fā) Server適應于面向連接的服務類型,而重復 Server適應于無連接的服務類型。
BSD UNIX更直觀地解釋網(wǎng)絡環(huán)境中進程通信的實現(xiàn)方法。
3.2.1 socket的基本概念
套接字是中間件抽象層,用于在應用程序?qū)雍蚑CP/IP協(xié)議套件之間的通信。它是一組接口。socket將復雜的TCP/IP協(xié)議系列隱藏在socket接口后面。用戶擁有了一套簡單的接口,從而使socket可以組織數(shù)據(jù),遵守指定的協(xié)議。
3.2.2 套接字通信機制
套接字允許位于不同計算機上的互聯(lián)進程執(zhí)行通信功能。使用套接字可在特定計算機上標記和定位特定進程的地址,以便可以將數(shù)據(jù)準確地傳輸?shù)侥繕诉M程。套接字包含3個參數(shù):通信目標IP地址、傳輸層協(xié)議(TCP或UDP)和端口號。IP地址用于標識目標計算機,端口號用于標識目標計算機上的特定進程。套接字之間的連接分為3個階段:監(jiān)視服務器、請求客戶端和確認連接[2]。
對于UNIX系統(tǒng),socket調(diào)用是網(wǎng)絡的輸入/輸出。
3.3.1 創(chuàng)建socket—socket()
應用程序在使用socket之前必須首先擁有一個socket號。這就相當于用戶在安裝電話時首先要向電話局申請一個電話號碼。
socket()向應用程序提供創(chuàng)建socket的手段,socket()調(diào)用的格式是:
Socketid=socket (af, type, protocol)
返回的Socketid值是一個整數(shù),申請一個屬于自己此次進程通信的socket號,創(chuàng)建socket,實際上是申請1個屬于自己此次進程通信的socket號,socket()一共有以下3個參數(shù):①地址族(address family af);②類型type;③協(xié)議protocol。它們分別代表socket使用的地址類型,創(chuàng)建socket的應用程序所希望的通信服務類型以及socket請求使用的協(xié)議。
3.3.2 指定本地地址—bind()
創(chuàng)建socket()并且調(diào)用,是完成socket通信創(chuàng)建的第一步。它僅在相關的五元組中指定協(xié)議,并且bind()系統(tǒng)調(diào)用會給出本地地址和本地端口。
bind()系統(tǒng)調(diào)用的格式是:bind(socketid,localaddr,addr elen)
其中,Socketid是本地的socket號;localaddr是本地地址,在TCP/IP族中它就是本地主機的IP地址;addrelen對應于IP地址長度。
3.3.3 建立套接字連接connect()和accept()
accept()和connect()調(diào)用終止兩個關聯(lián)的連接。其中,connect()用于建立連接。連接在這里有兩種含義,一種是在兩個socket之間進行通信,另一種是在傳輸層建立連接。例如,TCP的connect()連接調(diào)用主要用于面向連接的傳輸服務,而accept()調(diào)用用于面向連接的傳輸服務。無連接socket進程可以調(diào)用connect()。但是,此時本地系統(tǒng)和遠程系統(tǒng)之間沒有真正的連接,它實際上通知操作系統(tǒng),它將指定的套接字數(shù)據(jù)發(fā)送到此套接字。
3.3.4 接收socket連接—listen()
listen()調(diào)用是用于面向連接Server,它表示同意接受連接。
listen()調(diào)用格式是:listen(socketid,quelen)
其中,Socketid是本地socket號,表示Server可以在此socket號上接受服務請求,quelen表示請求的隊列長度。
3.3.5 發(fā)送數(shù)據(jù)write()writev()與send()sendto()sendmsg()
用于面向連接傳輸write()writev()send()調(diào)用的格式比較一致,例如:
緩沖發(fā)送:write(socketid,buffbuffon)
集中發(fā)送:writev(socketid,iovecor,vectorlen)
可控緩沖發(fā)送:send(socketid,buff,buffer,flags)
3.3.6 接收數(shù)據(jù)read()readv()與recvfrom()recvmsg()
接收數(shù)據(jù)調(diào)用read()ready()與recvfrom()recvmsg()和發(fā)送數(shù)據(jù)調(diào)用是對應的。不同之處在于,發(fā)送數(shù)據(jù)調(diào)用的Buff是指針,而接收數(shù)據(jù)調(diào)用中的Buff是實際讀出的值。
Client/Server模式直至今天仍然有其自身的優(yōu)勢,這種應用程序體系結(jié)構仍將長期存在。學習和了解這種模式,有助于人們理解Client/Server模式,對基于這種模式的應用程序開發(fā)和服務的搭建都很有益處。