TCP/IP 工作模式

TCP/IP 應用層與應用程序

TCP/IP 起源於二十世紀 60 年代末美國政府資助的一個分組交換網絡研究項目,它是一個真正的開放協議,很多不同廠家生產各種型號的計算機,它們運行完全不同的操作系統,但 TCP/IP 協議組件允許它們互相進行通信。現在 TCP/IP 已經從一個只供一些科學家使用的小實驗網成長爲一個由成千上萬的計算機和用戶構成的全球化網絡,TCP/IP 也已成爲全球因特網(Internet)的基礎,越來越多的 TCP/IP 互聯網應用和企業商業應用正在改變着世界。

TCP/IP 通訊協議採用了四層的層級模型結構(注:這與 OSI 七層模型不相同),每一層都調用它的下一層所提供的網絡任務來完成自己的需求。TCP/IP 的每一層都是由一系列協議來定義的。這 4 層分別爲:

 

  • 應用層 (Application) :應用層是個很廣泛的概念,有一些基本相同的系統級 TCP/IP 應用以及應用協議,也有許多的企業商業應用和互聯網應用。
  • 傳輸層 (Transport) :傳輸層包括 UDP 和 TCP,UDP 幾乎不對報文進行檢查,而 TCP 提供傳輸保證。
  • 網絡層 (Network) :網絡層協議由一系列協議組成,包括 ICMP、IGMP、RIP、OSPF、IP(v4,v6) 等。
  • 鏈路層 (Link) :又稱爲物理數據網絡接口層,負責報文傳輸。

圖1顯示了 TCP/IP 層級模型結構,應用層之間的協議通過逐級調用傳輸層(Transport layer)、網絡層(Network Layer)和物理數據鏈路層(Physical Data Link)而可以實現應用層的應用程序通信互聯。

應用層需要關心應用程序的邏輯細節,而不是數據在網絡中的傳輸活動。應用層其下三層則處理真正的通信細節。在 Internet 整個發展過程中的所有思想和着重點都以一種稱爲 RFC(Request For Comments)的文檔格式存在。針對每一種特定的 TCP/IP 應用,有相應的 RFC 文檔。一些典型的 TCP/IP 應用有 FTP、Telnet、SMTP、SNTP、REXEC、TFTP、LPD、SNMP、NFS、INETD 等。RFC 使一些基本相同的 TCP/IP 應用程序實現了標準化,從而使得不同廠家開發的應用程序可以互相通信。


圖 1 TCP/IP 層級模型結構

然而除了這些已經實現標準化的系統級 TCP/IP 應用程序外,在企業商業應用和互聯網應用開發中,存在着大量的商業應用程序通信互聯問題。如圖 1 顯示,其中的應用層所包含應用程序主要可以分成兩類,即系統級應用和商業應用,互聯網商業應用是商業應用中的主要形式之一。

不同開發商和用戶在開發各自商業應用通信程序時也存在有許多不同的設計方式。關於 TCP/IP 應用層以下的技術文獻與書籍早已是汗牛充棟,但是關於 TCP/IP 應用本身,尤其是關於商業應用的通信設計模式技術討論方面的文章還是比較少的。TCP/IP 應用通信設計模式實際上是在 TCP/IP 基礎編程之上的一種應用編程設計方式,也屬於一種應用層協議範疇,其可以包含有 TCP/IP 地址族模式設計、I/O 模式設計、通信連接模式設計以及通信數據格式設計等。鑑於目前討論 TCP/IP 商業應用程序設計模式問題這方面的文章還很少見,本文嘗試給出一些通信連接模式設計中共同的概念與一些典型的設計模式,在以後的文章中將繼續討論地址族模 式設計、I/O 模式設計、以及通信數據格式設計等方面的模式設計實現話題。

通信連接模式設計主要考慮內容有:

  • 通信兩端程序建立通信方式
  • 通信連接方式
  • 通信報文發送與接收方式

以下內容將介紹建立通信的 Client/Server 模型,然後逐一介紹通信連接模式設計所需要考慮的這些內容。





回頁首



傳輸層接口 APIs 與 TCP/IP 應用程序 C/S 模型

傳輸層接口 APIs

TCP/IP 應用層位於傳輸層之上,TCP/IP 應用程序需要調用傳輸層的接口才能實現應用程序之間通信。目前使用最廣泛的傳輸層的應用編程接口是套接字接口(Socket)。Socket APIs 是於 1983 年在 Berkeley Socket Distribution (BSD) Unix 中引進的。 1986 年 AT&T 公司引進了另一種不同的網絡層編程接口 TLI(Transport Layer Interface),1988 年 AT&T 發佈了一種修改版的 TLI,叫做 XTI(X/open Transport interface)。XTI/TLI 和 Socket 是用來處理相同任務的不同方法。關於 TCP/IP APIs 使用文章與書籍已相當多,本文則是側重於如何組合使用這些 APIs 來進行 TCP/IP 應用程序連接模式設計,並歸納出幾種基本應用連接模式。

如圖 2 顯示,應用層是通過調用傳輸層接口 APIs(Socket 或 XTI/TLI)來與傳輸層和網絡層進行通信的。


圖 2 傳輸層接口

不管是使用何種編程接口,要在兩個機器或兩個程序之間建立通信,通信雙方必須建立互相一致的通信模式。如果雙方的通信設計模式不一致就無法建立有效的通信連接。

以下是經常使用的 socket APIs,是建立 TCP/IP 應用程序的標準接口,也是影響 TCP/IP 應用程序通信方式的幾個主要 APIs,不同 APIs 組合再結合系統調用可以實現不同方式的應用。Sockets 支持多種傳輸層和網絡層協議,支持面向連接和無連接的數據傳輸,允許應用分佈式工作。

  • socket():是用來創建一個 socket,socket 表示通信中的一個節點,其可以在一個網絡中被命名,用 socket 描述符表示,socket 描述符類似於 Unix 中的文件描述符。
  • bind():是用來把本地 IP 層地址和 TCP 層端口賦予 socket。
  • listen() :把未連接的 socket 轉化成一個等待可連接的 socket,允許該 socket 可以被請求連接,並指定該 socket 允許的最大連接數。
  • accept():是等待一個連接的進入,連接成功後,產生一個新的 socket 描述符,這個新的描述符用來建立與客戶端的連接。
  • connect():用來建立一個與服務端的連接。
  • send():發送一個數據緩衝區,類似 Unix 的文件函數 write()。另外 sendto() 是用在無連接的 UDP 程序中,用來發送自帶尋址信息的數據包。
  • recv():接收一個數據緩衝區,類似 Unix 的文件函數 readI()。另外 recvfrom() 是用在無連接的 UDP 程序中,用來接收自帶尋址信息的數據包。
  • close():關閉一個連接

Client/Server 模型

Sockets 是以 Client 和 Server 交互通信方式來使用的。典型的系統配置是把 Server 放在一臺機器中,而把 Client 放在另一臺機器中,Client 連接到 Server 交換信息。一個 socket 有一系列典型的事件流。例如,在面向連接的 Client/Server 模型中,Server 端的 socket 總是等待一個 Client 端的請求。要實現這個請求,Server 端首先需要建立能夠被 Client 使用的地址,當地址建立後,Server 等待 Client 請求服務。當一個 Client 通過 socket 連接到 Server 後,Client 與 Server 之間就可以進行信息交換。Client/Server 是通信程序設計的基本模式。從軟件開發的角度講,TCP/IP 應用程序都是基於 Client/Server 方式的。注意本篇文章以下 Client/Server 概念是針對程序內部調用 Socket API 所講的概念,與針對整個程序甚至針對機器而講的客戶端 / 服務器概念有所不同。用 Server APIs 建立的程序可以被當作客戶端使用,用 Client APIs 建立的程序也可以被用作服務器端使用。建立 Server 需要的 APIs 有 socket(), bind(), listen(), accept(),建立 Client 需要的 APIs 有 Socket(), Connect()。在實際應用開發中,同一個程序裏往往同時可以有 Client 和 Server 的代碼,或者多種形式的組合。在實際應用編程中,針對 Socket APIs 不同有效組合,結合系統調用可以有多種複雜的設計變化。

面向連接的應用編程存在三類基本的不同級別的設計方式範疇,根據 Socket APIs 從上到下順序依次是:

  • Client/Server 通信建立方式
  • Client/Server 通信連接方式
  • Client/Server 通信發送與接收方式

下面內容以面向連接的 Socket 應用編程爲例來說明這幾種不同通信範疇的設計實現。





回頁首



Client/Server 建立方式設計概述

一個 Client 連接一個 Server

如果只有兩臺機器之間連接,那麼一個是 Client,另一個是 Server,如下面圖 3 所示。這是最簡單的 TCP/IP 的應用,也是 TCP/IP 應用早期的 Peer to Peer (P2P) 概念。其流程基本如圖 4 所示。


圖 3 TCP/IP 應用單點 Client/Server

圖 4 顯示了 TCP/IP 應用編程最基本的 Client/Server 模式,顯示了基本的 Client/Server 通信所需要調用的 Socket APIs 以及順序。


圖 4 TCP/IP 應用編程基本 Client/Server 模式

多個 Client 連接一個 Server

多個 Client 同時連接一個 Server 是 TCP/IP 應用的主流形式,如圖 5 所示,其中 Client 連接數可以從幾個到成千上萬。


圖 5 TCP/IP 應用多 Client 端的 Client/Server

由於 socket APIs 缺省方式下都是阻塞方式的,實現多個 Client 同時連接一個 Server 就需要特別的設計。其實現方式可以有多種不同的設計,這其中也涉及 I/O 模式設計。下面將展開介紹其中幾種設計形式。

利用一個 Client 連接一個 Server 形式實現多 Client 連接

從程序設計角度講,只要 Client 和 Server 端口是一對一形式,那麼就屬於一個 Client 連接一個 Server 形式。在處理多個 Client 端連接時,Server 端輪流使用多個端口建立多個 Client-Server 連接,連接關閉後,被釋放端口可以被循環使用。在這種多連接形式中需要謹慎處理 Client 端如何獲取使用 Server 端的可用端口。比如圖 6 顯示 Server 有一個服務於所有進程的進程可以先把 Server 端的可用端口發送給 Client 端,Client 端再使用該端口建立連接來處理業務。Server 針對每一個 Client 連接用一個專門的進程來處理。由於可用端口數有限,Server 用一個有限循環來處理每一個可用的端口連接。由於新端口需要用 bind() 來綁定,所以需要從 bind() 開始到 close() 結束都需要包含在循環體內。


圖 6 利用一對一 Client-Server 模式實現多 Client 連接

使用多個 accept() 實現多 Client 連接

多進程 Server 一般有一個專注進程是服務於每一個連接的。當 Client 端完成連接後,專注進程可以循環被另外的連接使用。使用多個 accept() 也可以實現處理多 Client 連接。多 accept() 的 Server 也只有一個 socket(),一個 bind(),一個 listen(),這與通常情況一樣。但是它建立許多工作子進程,每一個工作子進程都有 accept(),這樣可以爲每一個 Client 建立 socket 描述符。如圖 7 所示,由於 accept() 連接成功後,會產生一個新的 socket 描述符,這樣通過循環多進程利用 accept() 產生的多 socket 描述符就可以與多個 Client 進行連接通信。循環體是從 accept() 開始到 close() 結束的。


圖 7 使用多 accept() 實現多 Client 連接

使用併發 Server 模式實現多 Client 連接

併發服務器模式曾經是 TCP/IP 的主流應用程序設計模式,得到廣泛使用,目前互聯網上仍有相當多的應用使用此種模式。其設計思路是在 accept 之後 fork 出一個子進程。因爲 socket 會產生監聽 socket 描述符 listenfd,accept 會產生連接 socket 描述符 connfd。連接建立後,子進程繼承連接描述符服務於 Client,父進程則繼續使用監聽描述符等待另外一個 Client 的連接請求,以產生另外一個連接 socket 描述符和子進程。如圖 8 所示,accept() 接收到一個 Client 連接後,產生一個新的 socket 描述符,通過 fork() 系統調用,用一個子進程來處理該 socket 描述符的連接服務。而父進程可以立即返回到 accept(),等待一個新的 Client 請求,這就是典型的併發服務器模式。併發服務器模式同時處理的最大併發 Client 連接數由 listen() 的第二個參數來指定。


圖 8 TCP/IP 應用併發 Server

使用 I/O 多路技術實現多 Client 連接

以上三種連接設計,多 Server 端口、多 accept() 和併發服務器模式,都是通過 fork() 系統調用產生多進程來實現多 Client 連接的。使用 I/O 多路技術也可以同時處理多個輸入與輸出問題,即用一個進程同時處理多個文件描述符。I/O 多路技術是通過 select() 或 poll() 系統調用實現的。poll() 與 select() 功能完全相同,但是 poll() 可以更少使用內存資源以及有更少的錯誤發生。select() 調用需要與操作文件描述符集的 APIs 配合使用。select() 系統調用可以使一個進程檢測多個等待的 I/O 是否準備好,當沒有設備準備好時,select() 處於阻塞狀態中,其中任一設備準備好後,select() 函數返回調用。select() API 本身也有一個超時時間參數,超時時間到後,無論是否有設備準備好,都返回調用。其流程如圖 9 所示。在 socket APIs listen() 和 accept() 之間插入 select() 調用。使用這三個宏 FD_ZERO()、FD_CLR() 和 FD_SET(),在調用 select() 前設置 socket 描述符屏蔽位,在調用 select() 後使用 FD_ISSET 來檢測 socket 描述符集中對應於 socket 描述符的位是否被設置。 FD_ISSET() 就相當通知了一個 socket 描述符是否可以被使用,如果該 socket 描述符可用,則可對該 socket 描述符進行讀寫通信操作。通常,操作系統通過宏 FD_SETSIZE 來聲明在一個進程中 select() 所能操作的文件或 socket 描述符的最大數目。更詳細的 I/O 多路技術實現,可以參考其他相關文獻。


圖 9 I/O 多路技術實現多連接的 Server

一個 Client 連接多個 Server

一個 Client 連接多個 Server 這種方式很少見,主要用於一個客戶需要向多個服務器發送請求情況,比如一個 Client 端掃描連接多個 Server 端情況。如圖 10 所示。此種方式設計主要是 Client 端應用程序的邏輯設計,通常需要在 Client 端設計邏輯循環來連接多個 Server,在此不做更多描述。


圖 10 單 Client 對多 Server

複雜 Client/Server 設計與現代 P2P

最近幾年,對等網絡技術 ( Peer-to-Peer,簡稱 P2P) 迅速成爲計算機界關注的熱門話題之一,以及影響 Internet 未來的科技之一。與早期點對點 (Peer to Peer) 的 Client/Server 模式不同,現在的 P2P 模式是指每個結點既可充當服務器,爲其他結點提供服務,同時也可作爲客戶端享用其他結點提供的服務。實際上 P2P 模式仍然是基於 Client/Server 模式的,每個通信節點都既是 Server,又是 Client,P2P 是基於複雜 Client/Server 設計的 TCP/IP 應用。圖 11 顯示 P2P 模式下兩個用戶 PC 之間的對等連接。


圖 11 P2P 模式

在技術上,P2P 本身是基於 TCP/IP Client/Server 技術的一種設計模式思想, P2P 也屬於網絡應用層技術,與 Web 和 FTP 等應用是並列的。只是 P2P 應用在設計實現上更要複雜的多。P2P 技術實現的協同工作是無需專門的服務器支持的 (Serverless),這裏的服務器概念與 Client/Server 中的 Server 概念是不一樣的。在傳統意義上中心服務器機器上往往運行的是 TCP/IP 應用的 Server 端程序,所以傳統意義上的 Server 概念在機器與應用上是重合的。如果更改 TCP/IP 的應用設計,使應用程序既可做 Server 又可做 Client,就可以實現無中心服務器的 P2P 模式。

在設計模式上,P2P 模式實現了網絡終端用戶不依賴中心服務器或者服務商而直接進行信息和數據交換的可能,因此 P2P 正在改變着整個互聯網的一些基礎應用,從而極大地增加了用戶之間的信息溝通和交流能力。目前互聯網的 P2P 應用與網絡都正在飛速發展,一些典型的 P2P 應用程序比如有 BitTorrent, eDonkey 等,另外一些即時通信(IM)類軟件比如 MSN、QQ 等也正在向無中心服務器模式轉變。無中心服務器的 Internet 應用程序大大降低應用提供商的運營成本,而且減少人們對於 Server 穩定性的依賴。





回頁首



Client/Server 通信連接方式設計

Client/Server 通信方式建立後,下一步就需要考慮通信連接的方式,主要有兩種方式的連接,即長連接通信與短連接通信。通信連接方式涉及到的 APIs 主要是 connect() 和 accept()。要實現某種 Client/Server 方式,就必須考慮用某種特定的連接方式。

短連接通信

短連接通信是指 Client 方與 Server 方每進行一次通信報文收發交易時才進行通訊連接,交易完畢後立即斷開連接。此種方式常用於多個 Client 連接一個 Server 情況,常用於機構與用戶之間通信,比如 OLTP(聯機事務處理)類應用。在短連接情況下,Client 端完成任務後,就關閉連接並退出。在 Server 端,可以通過循環 accept(),使 Server 不會退出,並連續處理 Client 的請求。圖 12 顯示了一般情況下短連接通信模式的 Socket 事件流,不同設計的連接多 Client 的 Server 有不同的循環流程。


圖 12 短連接模式通信

長連接通信

長連接通信是指 Client 方與 Server 方先建立通訊連接,連接建立後不會斷開,然後再進行報文發送和接收,報文發送與接收完畢後,原來連接不會斷開而繼續存在,因此可以連續進行交易報文的發送 與接收。這種方式下由於通訊連接一直存在,其 TCP/IP 狀態是 Established,可以用操作系統的命令 netstat 查看連接是否建立。由於在長連接情況下,Client 端和 Server 端一樣可以固定使用一個端口,所以長連接下的 Client 也需要使用 bind() 來綁定 Client 的端口。在長連接方式下,需要循環讀寫通信數據。爲了區分每一次交易的通信數據,每一次交易數據常常需要在數據頭部指定該次交易的長度,接收 API 需要首先讀出該長度,然後再按該長度讀出指定長度的字節。長連接方式常用於一個 Client 端對一個 Server 端的通訊,一般常用於機構與機構之間的商業應用通信,以處理機構之間連續的大量的信息數據交換。或者說可用於兩個系統之間持續的信息交流情況。通常爲了加 快兩個系統之間的信息交流,通常還需要建立幾條長連接的並行通信線路。圖 13 顯示了一般情況下長連接通信模式的 socket 事件流,可見其最大特點是 Client 和 Server 都有循環體,而且循環體只包含讀寫 APIs。


圖 13 長連接模式通信





回頁首



Client/Server 通信發送與接收方式設計

在通信數據發送與接收之間也存在不同的方式,即同步和異步兩種方式。這裏的同步和異步與 I/O 層次的同異步概念不同。主要涉及 socket APIs recv() 和 send() 的不同組合方式。

同步發送與接收

從應用程序設計的角度講,報文發送和接收是同步進行的,既報文發送後,發送方等待接收方返回消息報文。同步方式一般需要考慮超時問題,即報文發出去後發送 方不能無限等待,需要設定超時時間,超過該時間後發送方不再處於等待狀態中,而直接被通知超時返回。同步發送與接收經常與短連接通信方式結合使用,稱爲同 步短連接通信方式,其 socket 事件流程可如上面的圖 12 所示。

異步發送與接收

從應用程序設計的角度講,發送方只管發送數據,不需要等待接收任何返回數據,而接收方只管接收數據,這就是應用層的異步發送與接收方式。要實現異步方式, 通常情況下報文發送和接收是用兩個不同的進程來分別處理的,即發送與接收是分開的,相互獨立的,互不影響。異步發送與接收經常與長連接通信方式結合使用, 稱爲異步長連接通信方式。從應用邏輯角度講,這種方式又可分雙工和單工兩種情況。

異步雙工

異步雙工是指應用通信的接收和發送在同一個程序中,而有兩個不同的子進程分別負責發送和接收,異步雙工模式是比較複雜的一種通信方式,有時候經常會出現在 不同機構之間的兩套系統之間的通信。比如銀行與銀行之間的信息交流。它也可以適用在現代 P2P 程序中。如圖 14 所示,Server 和 Client 端分別 fork 出兩個子進程,形成兩對子進程之間的連接,兩個連接都是單向的,一個連接是用於發送,另一個連接用於接收,這樣方式的連接就被稱爲異步雙工方式連接。


圖 14 長連接異步雙工模式

異步單工

應用通信的接收和發送是用兩個不同的程序來完成,這種異步是利用兩對不同程序依靠應用邏輯來實現的。圖 15 顯示了長連接方式下的異步單工模式,在通信的 A 和 B 端,分別有兩套 Server 和 Client 程序,B 端的 Client 連接 A 端的 Server,A 端的 Server 只負責接收 B 端 Client 發送的報文。A 端的 Client 連接 B 端的 Server,A 端 Client 只負責向 B 端 Server 發送報文。


圖 15 長連接異步單工模式






典型通信連接模式

綜上所述,在實際 TCP/IP 應用程序設計中,就連接模式而言,我們需要考慮 Client/Server 建立方式、Client/Server 連接方式、Client/Server 發送與接收方式這三個不同級別的設計方式。實際 TCP/IP 應用程序連接模式可以是以上三類不同級別 Client/Server 方式的組合。比如一般 TCP/IP 相關書籍上提供的 TCP/IP 範例程序大都是同步短連接的 Client/Server 程序。有的組合是基本沒有實用價值的,比較常用的有價值的組合是以下幾種:

  • 同步短連接 Server/Client
  • 同步長連接 Server/Client
  • 異步短連接 Server/Client
  • 異步長連接雙工 Server/Client
  • 異步長連接單工 Server/Client

其中異步長連接雙工是較爲複雜的一種通信方式,有時候經常會出現在不同銀行或不同城市之間的兩套系統之間的通信,比如國家金卡工程。由於這幾種通信方式比較固定,所以可以預先編制這幾種通信方式的模板程序。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章