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