一、程序的實用背景
上網的朋友越來越多,遇到的問題也越來越多,最常見的就是關於域名服務器(DNS)、郵件服務(SMTP)和POP3的配置問題。例如,選用哪一個DNS,202.96.0.133還是202.96.26.243?記不清ISP的郵件服務器和域名服務器的IP地址,202.96.26.243還是245?
另外一個問題就是,我們在下載文件的時候,往往面臨從多個不同主機下載的選擇(象sunsite有數十個鏡像站點)。那麼,選擇哪一個站點進行下載是最快的呢?
筆者為此編寫了一個應用程序,試圖對Internet的常用的網絡通信端口(如Web、Email、FTP等)進行連接測試,獲得服務端口的狀態和響應時間指標,從而為我們更有效的使用Internet提供准確的參考數據。筆者為該程序命名為Tester(測試者),從後面敘述不難發現,Tester還可以作為簡單的Internet系統性能測試工具來使用。
雖然Tester也涉及了其它的編程方法,但就總體而言,Tester屬於Socket應用程序。所以我們先從Socket編程的模型入手,介紹Tester程序的設計與實現。
二、Socket編程模型
Socket是網絡通信的一個端點。我們知道,網絡通信通常指兩台主機或兩個進程,通過網絡傳遞它們之間的數據,這樣的過程可以理解為網絡的一次對話(Session)。網絡對話的每一端就成為網絡通信的端點,即網絡通信實體的最小單位。當使用Socket接口對網絡通信編程時,Socket是網絡通信過程中端點的抽象表示。大多數網絡通信采用客戶/服務器模型,客戶/服務器模型按照端點的工作性質來區分通信雙方的端點。例如,客戶/服務器模型將啟動網絡服務請求的端點視作客戶進程或客戶程序;對客戶請求作出響應的端點是服務器進程或服務器程序。
為了進行網絡通信,程序在網絡的對話的每一端都需要一個Socket,即客戶端的Socket和服務器端的Socket。兩個Socket之間的連接可以是面向連接的也可以是無連接的。雖然從目前看,Socket編程已經不再局限於UNIX系統,但是Socket接口在網絡通信時仍然使用UNIX系統I/O概念,Socket接口模型仍然采用Open-Read-Write-Close方式。Socket編程的包括幾個主要步驟:
1、建立Socket;
2、配置Socket;
3、通過Socket發送數據;
4、通過Socket接收數據;
5、關閉Socket。
三、CSocket編程模型
對於網絡通信編程的初學者來說,直接使用上述的socket模型會感覺困難和復雜。VisualC++的MFC(基礎類庫)提供了一些封裝好的對象可供使用,這些對象的概念相對簡單,編程相對容易。Tester程序就是使用MFC的幾個與socket相關的類來實現的。
在服務器Socket和客戶Socket之間建立通信的過程如下文所述。
1、創建CSocket對象。
2、使用該對象產生SOCKET句柄。
3、如果socket是客戶,調用CAsyncSocket::Connect,連接本地的Socket和服務器Socket;
如果socket是服務器,調用CAsyncSocket::Listen,開始偵聽從客戶端來的訪問請求,如果收到請求,調用CAsyncSocket::Accept進行接收處理。
4、建立CSocketFile對象,並且使該對象與CSocket對象具備一定的聯系;
5、建立CArchive對象,以便實現卸裝(接收)數據和存儲(發送)數據的目的。當然,該CArchive對象應該與前面的CSocketFile對象建立聯系;
6、使用CArchive對象在客戶和服務器socket之間傳遞數據,從而實現服務器socket和客戶機socket之間的通信。值得注意的是,一個給定的CArchive對象只能在單一的方向上傳遞數據:或者接收或者發送。一般情況下,可能需要兩個CArchive對象來實現數據的雙向傳遞。
7、解析archive、socketfile、socket對象。