天天看點

CSocket 和CAsyncSocket類介紹

一、實作方法

微軟的MFC把複雜的WinSock API函數封裝到類裡,這使得編寫網絡應用程式更容易。CAsyncSocket類逐個封裝了WinSock API,為進階網絡程式員提供了更加有力而靈活的方法。這個類基于程式員了解網絡通訊的假設,目的是為了在MFC中使用WinSock,程式員有責任處理諸如阻塞、位元組順序和在Unicode與MBCS 間轉換字元的任務。為了給程式員提供更友善的接口以自動處理這些任務,MFC給出了CSocket類,這個類是由CAsyncSocket類繼承下來的,它提供了比CAsyncSocket更高層的WinSock API接口。Csocket類和CsocketFile類可以與Carchive類一起合作來管理發送和接收的資料,這使管理資料收發更加便利。CSocket對象提供阻塞模式,這對于Carchive的同步操作是至關重要的。阻塞函數(如Receive()、Send()、ReceiveFrom()、SendTo() 和Accept())直到操作完成後才傳回控制權,是以如果需要低層控制和高效率,就使用CasyncSock類;如果需要友善,則可使用Csocket類。

CSocket類是由CAsyncSocket繼承而來的,事實上,在MFC中CAsyncSocket 逐個封裝了WinSock API,每個CAsyncSocket對象代表一個Windows Socket對象,使用CAsyncSocket 類要求程式員對網絡程式設計較為熟悉。相比起來,CSocket類是CAsyncSocket的派生類,繼承了它封裝的WinSock API。

一個CSocket對象代表了一個比CAsyncSocket對象更高層次的Windows Socket的抽象,CSocket類與CSocketFile類和CArchive類一起工作來發送和接收資料,是以使用它更加容易使用。CSocket對象提供阻塞模式,因為阻塞功能對于CArchive的同步操作是至關重要的。在這裡有必要對阻塞的概念作一解釋:一個socket可以處于"阻塞模式"或"非阻塞模式",當一個套接字處于阻塞模式(即同步操作)時,它的阻塞函數直到操作完成才會傳回控制權,之是以稱為阻塞是因為此套接字的阻塞函數在完成操作傳回之前什麼也不能做。如果一個socket處于非阻塞模式(即異步操作),則會被調用函數立即傳回。在CAsyncSocket類中可以用GetLastError 成員函數查詢最後的錯誤,如果錯誤是WSAEWOULDBLOCK則說明有阻塞,而CSocket絕不會傳回WSAEWOULDBLOCK,因為它自己管理阻塞。微軟建議盡量使用非阻塞模式,通過網絡事件的發生而通知應用程式進行相應的處理。但在CSocket類中,為了利用CArchive 處理通訊中的許多問題和簡化程式設計,它的一些成員函數總是具有阻塞性質的,這是因為CArchive類需要同步的操作。

在Win32環境下,如果要使用具有阻塞性質的套接字,應該放在獨立的工作線程中處理,利用多線程的方法使阻塞不至于幹擾其他線程,也不會把CPU時間浪費在阻塞上。多線程的方法既可以使程式員享受CSocket帶來的簡化程式設計的便利,也不會影響使用者界面對使用者的反應。

CAsyncSocket類程式設計模型

在一個MFC應用程式中,要想輕松處理多個網絡協定,而又不犧牲靈活性時,可以考慮使用CAsyncSocket類,它的效率比CSocket 類要高。CAsyncSocket類針對位元組流型套接字的程式設計模型簡述如下:

1、構造一個CAsyncSocket對象,并用這個對象的Create成員函數産生一個Socket句柄。可以按如下兩種方法構造:

CAsyncSocket sock; //使用預設參數産生一個位元組流套接字

Sock.Create();

或在指定端口号産生一個資料報套接字

CAsyncSocket*pSocket=newCAsyncSocket;

int nPort=27;

pSocket->Create(nPort,SOCK-DGRAM);

第一種方法在棧上産生一個CAsyncSocket對象,而第二種方法在堆上産生CAsyncSocket對象;第一種方法中Create()成員函數用預設參數産生一個位元組流套接字,第二種方法中用Create()成員函數在指定的端口産生一個數字報套接字。Create()函數的原型為:

BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM,

LPCTSTR lpszSocketAddress = NULL );

該函數的參數有:

1)端口,UINT類型。注意:如果是服務方,則使用一個衆所周知的端口供服務方連接配接;如果是客戶方,典型做法是接受預設參數,使套接字可以自主選擇一個可用端口;

2)socket 類型,可以是SOCK-STREAM(預設值,位元組流)或SOCK-DGRAM(資料報);

3)socket的位址,例如"ftp.gliet.edu.cn"或"202.193.64.33"。

2、如是客戶方程式,用CAsyncSocket∷Connect()成員函數連接配接到服務方;如是服務方程式,用CAsyncSocket∷Listen()成員函數開始監聽,一旦收到連接配接請求,則調用CAsyncSocket∷Accept()成員函數開始接收。注意:CAsyncSocket ∷Accept()成員函數要用一個新的并且是空的CAsyncSocket對象作為它的參數,這裡所說的"空的"指的是這個新對象還沒有調用Create()成員函數。

3、調用其他的CAsyncSocket類的Receive()、ReceiveFrom()、Send()和SendTo()等成員函數進行資料通信。

4、通訊結束後,銷毀CAsyncSocket對象。如果是在棧上産生的CAsyncSocket對象,則對象超出定義的範圍時自動被析構;如果是在堆上産生,也就是用了new這個操作符,則必須使用delete操作符銷毀CAsyncSocket 對象。

CSocket類程式設計模型

使用CSocket對象涉及CArchive和CSocketFile 類對象。以下介紹的針對位元組流型套接字的操作步驟中,隻有第3步對于客戶方和服務方操作是不同的,其他步驟都相同。

1、構造一個CSocket對象。

2、使用這個對象的Create()成員函數産生一個socket對象。在客戶方程式中,除非需要資料報套接字,Create()函數一般情況下應該使用預設參數。而對于服務方程式,必須在調用Create時指定一個端口。需要注意的是,Carchive類對象不能與資料報(UDP)套接字一起工作,是以對于資料報套接字,CAsyncSocket和CSocket 的使用方法是一樣的。

3、如果是客戶方套接字,則調用CAsyncSocket ∷Connect()函數與服務方套接字連接配接;如果是服務方套接字,則調用CAsyncSocket∷Listen()開始監聽來自客戶方的連接配接請求,收到連接配接請求後,調用CAsyncSocket∷Accept()函數接受請求,建立連接配接。請注意Accept()成員函數需要一個新的并且為空的CSocket對象作為它的參數,解釋同上。

4、産生一個CSocketFile對象,并把它與CSocket 對象關聯起來。

5、為接收和發送資料各産生一個CArchive 對象,把它們與CSocketFile對象關聯起來。切記CArchive是不能和資料報套接字一起工作的。

6、使用CArchive對象的Read()、Write()等函數在客戶與服務方傳送資料。

7、通訊完畢後,銷毀CArchive、CSocketFile和CSocket對象

本文轉自

http://blog.163.com/[email protected]/blog/static/46316478200781382640696/

繼續閱讀