




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第2章 MFC Socket編程2.12.2MFC及其Socket類C/S模式下網(wǎng)絡(luò)程序的Socket通信實例2.3Socket程序的互通2 . 1 MFC及其Socket類2.1.1 MFC簡介MFC是很龐大的,以Visual C+ 6.0所帶的MFC 4.21為例,已經(jīng)包含了多達上百個類、結(jié)構(gòu)和接口!如圖2.1所示。2.1.1 MFC簡介該層次結(jié)構(gòu)可分為如下幾種不同的類型: 應(yīng)用程序框架; 圖形繪制的繪制對象; 文件服務(wù); 異常處理; 結(jié)構(gòu),如Lists、Arrays和Maps; Internet服務(wù); OLE 2; 數(shù)據(jù)庫;2.1.2 MFC中的Socket類1CAsyncSocket類
2、CAsyncSocket類是從MFC的根類CObject派生出來的,它在較低的級別上封裝Windows Socket API,因此類中包含的大部分成員函數(shù)和底層Winsock API函數(shù)有很多相似之處,有的甚至連名稱和參數(shù)叫法都是相同或相近的,CAsyncSocket類在MFC套接字類中的繼承位置如圖2.2所示。CAsyncSocket類的成員函數(shù)見表2.1。2.1.2 MFC中的Socket類2CSocket類及其相關(guān)類(1)CSocket類。CSocket類是從CAsyncSocket類派生而來的,它繼承了CAsyncSocket對Windows Socket API的封裝。與CAsync
3、Socket對象相比,CSocket對象代表了Windows Socket API的更高一級的抽象化。(2)CSocket與CArchive、CSocketFile類的配合使用。使用CSocket類編寫網(wǎng)絡(luò)程序,既可以使用如CAsyncSocket類網(wǎng)絡(luò)程序一樣的Send和Receive函數(shù)來收發(fā)信息,也可以與CSocketFile類和CArchive類一起管理數(shù)據(jù)的發(fā)送和接收。2 . 2 C/S模式下網(wǎng)絡(luò)程序的Socket通信實例2.2.1 客戶端服務(wù)器方式(C/S模式)1網(wǎng)絡(luò)程序的通用體系結(jié)構(gòu)客戶端服務(wù)器方式所描述的是進程之間服務(wù)和被服務(wù)的關(guān)系。在圖2.3中,主機A運行客戶端程序而主機B運
4、行服務(wù)器程序。2.2.1 客戶端服務(wù)器方式(C/S模式)2最簡單的Socket通信流程這里先來考慮一個只有客戶端向服務(wù)方發(fā)信息的單向通信,并且也只有客戶端會主動提出斷開連接的最簡單的情形(相反過程的原理是一樣的),其雙方Socket之間的關(guān)系如圖2.4所示。2.2.1 客戶端服務(wù)器方式(C/S模式)由上面這個過程很容易得出對應(yīng)的Socket通信流程,如圖2.5所示。2.2.2 CAsyncSocket類編程基礎(chǔ)1對象分析若要實現(xiàn)上節(jié)分析的Socket通信流程共需要三個套接字對象:客戶端一個(稱為“客戶Socket”);服務(wù)器兩個(一個用于監(jiān)聽,稱為“監(jiān)聽Socket”;另一個用于接收客戶發(fā)來的
5、信息,稱為“服務(wù)Socket”)。這三個套接字對象對應(yīng)三個Socket類,都繼承自CAsyncSocket,分別為它們?nèi)∶绫?.2所示(表中的類名也是后面程序中需要使用的)。Socket對象類 名客戶SocketCClientSocket監(jiān)聽SocketCListenSocket服務(wù)SocketCServerSocket2.2.2 CAsyncSocket類編程基礎(chǔ)2創(chuàng)建工程和套接字對象打開Visual Studio 2010環(huán)境,建立一個新的基于對話框的MFC項目,項目名稱為ChatClient,向?qū)У那皫醉撛O(shè)置同第1章程序,直到設(shè)置程序“高級功能”頁,因為接下來要編寫的是網(wǎng)絡(luò)程序,使用套
6、接字,因此必須勾選“Windows套接字”復(fù)選框,如圖2.6所示。2.2.2 CAsyncSocket類編程基礎(chǔ)后面步驟中一律采用默認設(shè)置,直到完成工程的創(chuàng)建。工程創(chuàng)建后,由前述分析,還需要創(chuàng)建類名為CClientSocket的客戶Socket對象,于是給工程添加類,選擇菜單命令“項目”“添加類”,如圖2.7所示。2.2.2 CAsyncSocket類編程基礎(chǔ)在彈出的“添加類”對話框中選擇“MFC類”項,單擊“添加”按鈕(如圖2.8所示)。2.2.2 CAsyncSocket類編程基礎(chǔ)在“MFC添加類向?qū)А睂υ捒蛑休斎腩惷癈ClientSocket”,由于要使用CAsyncSocket套接字
7、類編寫程序,所以選擇基類為“CAsyncSocket”,同時可以看出,向?qū)н€將自動為這個添加的類生成名為“ClientSocket.h”和“ClientSocket.cpp”的頭文件和源文件,如圖2.9所示。2.2.2 CAsyncSocket類編程基礎(chǔ)單擊“完成”按鈕,就會在類視圖中看到剛剛添加的類CClientSocket(如圖2.10所示)。2.2.2 CAsyncSocket類編程基礎(chǔ)3理清程序文件的組織結(jié)構(gòu)1)客戶端程序文件打開已經(jīng)創(chuàng)建好的客戶端工程,如圖2.11所示,在解決方案資源管理器中可以看到工程所有的程序文件。2.2.2 CAsyncSocket類編程基礎(chǔ)2)服務(wù)器的源文件同
8、理,服務(wù)器也對應(yīng)這幾種程序文件,打開服務(wù)器工程,可以看到它們(如圖2.12所示)。2.2.2 CAsyncSocket類編程基礎(chǔ)4用頭文件和類對象將程序源文件連成有機整體要使客戶端程序能夠創(chuàng)建和控制本地的Socket,需在在客戶端工程界面控制模塊的頭文件ChatClientDlg.h中添加如下兩行代碼:#include ClientSocket.h /使主界面程序能夠訪問Socket類的代碼文件CClientSocket m_ClientSocket;/為了后面與服務(wù)器通信而定義的Socket成員變量以上兩行代碼的添加位置見圖2.13中“/ADD”記號之間標出的部分。2.2.2 CAsyncS
9、ocket類編程基礎(chǔ)相反地,若要使Socket能夠訪問到主界面上的控件,以便能夠?qū)⒆约旱臓顩r隨時反映給主程序并在主界面上顯示出來,也需要在Socket源文件ClientSocket.cpp中添加頭文件聲明:#include ChatClientDlg.h同理,若要使服務(wù)器程序能夠創(chuàng)建和控制本地的Socket,也要在服務(wù)器工程界面控制模塊的頭文件ChatServerDlg.h中添加如下代碼:#include ListenSocket.h /使主界面程序能夠訪問監(jiān)聽Socket類的代碼文件#include ServerSocket.h /使主界面程序能夠訪問服務(wù)Socket類的代碼文件CServe
10、rSocket m_ServerSocket;/為了后面與客戶端通信而定義的Socket成員變量CListenSocket m_ListenSocket;/為了監(jiān)聽客戶端的連接請求而定義的Socket成員變量2.2.2 CAsyncSocket類編程基礎(chǔ)以上四行代碼的添加位置見圖2.14中“/ADD”記號之間標出的部分。2.2.2 CAsyncSocket類編程基礎(chǔ)相反地,分別在監(jiān)聽套接字和服務(wù)套接字的源文件中添加聲明。在ListenSocket.cpp中添加如下代碼:#include ChatServerDlg.h在ServerSocket.cpp中添加如下代碼:#include ChatS
11、erverDlg.h2.2.2 CAsyncSocket類編程基礎(chǔ)5簡單布置界面在客戶端“資源視圖”展開的目錄樹下雙擊Dialog文件夾下的第二個項目,轉(zhuǎn)到用戶界面設(shè)計工作區(qū)(如圖2.15所示),先將設(shè)計頁上的默認控件(一個靜態(tài)文字標簽和“確定”按鈕)刪除,留下“取消”按鈕做程序的“退出”按鈕之用。2.2.2 CAsyncSocket類編程基礎(chǔ)在完成的客戶端簡化界面(如圖2.16所示)上,包括IP地址控件、列表框各1個,文本框兩個(一個用于接收用戶輸入端口號,另一個用于接收用戶輸入的待發(fā)送文本信息),4個按鈕(其中“連接”、“斷開”、“發(fā)送”3個按鈕是我們添加的,“退出”按鈕由原來的“取消”按
12、鈕改變Caption屬性得到)。2.2.2 CAsyncSocket類編程基礎(chǔ)設(shè)計服務(wù)器的界面如圖2.17所示,同樣,為IP地址控件關(guān)聯(lián)變量ServerIP,為文本框控件關(guān)聯(lián)int型變量sPort,為列表框關(guān)聯(lián)變量m_ListWords。2.2.2 CAsyncSocket類編程基礎(chǔ)6添加核心代碼到目前為止,已經(jīng)有了一個程序框架,接下來添加核心源代碼。先來回顧一下前面設(shè)計的那個最簡單的Socket通信流程,如圖2.18所示。2.2.2 CAsyncSocket類編程基礎(chǔ)按照調(diào)用方式可將這些函數(shù)分為兩大類。一類是由程序主動調(diào)用的,這類函數(shù)有Creat、Close、Connect、Send、Lis
13、ten、Accept,在源代碼中很容易找到調(diào)用它們的程序語句;另一類是由系統(tǒng)的某個網(wǎng)絡(luò)事件觸發(fā)的,如OnConnect、OnAccept、OnReceive、OnClose,網(wǎng)絡(luò)事件的觸發(fā)時機和發(fā)生順序不確定,因此不能事先編寫流程,而在程序運行期間視實際情況觸發(fā),由系統(tǒng)自動調(diào)用,因此源代碼中找不到調(diào)用這些函數(shù)的語句。2.2.2 CAsyncSocket類編程基礎(chǔ)從圖2.18已經(jīng)標注了所用函數(shù)的通信流程圖,可以進一步得出如圖2.19所示的源代碼組織框圖。2.2.2 CAsyncSocket類編程基礎(chǔ)7源代碼完全剖析(1)客戶端源碼??蛻舳擞脩羰紫戎鲃影l(fā)起連接,以下是“連接”按鈕的事件過程,位于C
14、hatClientDlg.cpp文件中:/連接服務(wù)器BYTE nFild4;CString sIP;UpdateData();m_ServerIP.GetAddress(nFild0,nFild1,nFild2,nFild3);sIP.Format(%d.%d.%d.%d,nFild0,nFild1,nFild2,nFild3);m_ClientSocket.Create();/創(chuàng)建客戶端Socketm_ClientSocket.Connect(sIP,m_sPort);/發(fā)起連接請求2.2.2 CAsyncSocket類編程基礎(chǔ)Create()函數(shù)原型如下:BOOL Create(UINT
15、nSocketport = 0, int nSocketType = SOCK_STREAM, long lEvent = FD_READ FD_WRITEFD_OOBFD_ACCEPTFD_CONNECTFD_CLOSE,LPCTSTR lpszSocketaddress = NULL);Connect()函數(shù)用于未連接的數(shù)據(jù)流或數(shù)據(jù)報套接字建立連接。其函數(shù)原型如下:BOOL Connect(LPCTSTR lpszHostAddress, UINT nHostPort);BOOL Connect(const SOCKADDR*lpSockAddr, int nSockAddrLen);2.
16、2.2 CAsyncSocket類編程基礎(chǔ)客戶端也可以隨時主動斷開通信連接,下面是“斷開”按鈕的事件過程:/斷開與服務(wù)器的連接m_ClientSocket.Close();/關(guān)閉客戶端Socketm_ListWords.AddString(從服務(wù)器斷開);Close()函數(shù)用來關(guān)閉套接字并釋放Socket描述符,其函數(shù)原型如下:virtual void Close();客戶端可以向服務(wù)器發(fā)送信息,“發(fā)送”按鈕的事件過程如下:/向服務(wù)器發(fā)信息UpdateData();m_ClientSocket.Send(m_sWords,m_sWords.GetLength();/發(fā)信息m_ListWords
17、.AddString(發(fā)送: + m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);Send()函數(shù)通過數(shù)據(jù)報或者數(shù)據(jù)流向?qū)Ψ教捉幼职l(fā)送數(shù)據(jù),其函數(shù)原型如下:virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);2.2.2 CAsyncSocket類編程基礎(chǔ)接下來要編寫的是第二類(即網(wǎng)絡(luò)事件響應(yīng))函數(shù),源碼中無法找到調(diào)用它們的語句,它們是由系統(tǒng)自動觸發(fā)的,通過如圖2.20所示的屬性窗口來添加這類函數(shù)的代碼。2.2.2 CAsyncSocket類編
18、程基礎(chǔ)OnConnect()函數(shù)代碼如下:/確認客戶端是否成功連接到服務(wù)器if(nErrorCode)AfxMessageBox(連接失敗,請您重試!);return;(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(連接成功);(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount()- 1);2.2.2 CAsync
19、Socket類編程基礎(chǔ)(2)服務(wù)器源碼(ChatServerDlg.cpp文件中)?!伴_始監(jiān)聽”按鈕的事件過程如下:/監(jiān)聽開始,服務(wù)器等待連接請求的到來BYTE nFild4;CString sIP,sP;UpdateData();m_ServerIP.GetAddress(nFild0,nFild1,nFild2,nFild3);sIP.Format(%d.%d.%d.%d,nFild0,nFild1,nFild2,nFild3);sP.Format(%d,m_sPort);m_ListenSocket.Create(m_sPort,1,FD_ACCEPT,sIP); /創(chuàng)建服務(wù)器監(jiān)聽Soc
20、ketm_ListenSocket.Listen(1); /開始監(jiān)聽m_ListWords.AddString(在 + sIP + : + sP + 監(jiān)聽);Listen()函數(shù)用于偵聽連接請求,原型如下:BOOL Listen(int nConnectionBacklog = 5);2.2.2 CAsyncSocket類編程基礎(chǔ)“停止監(jiān)聽”按鈕的事件過程如下:/停止監(jiān)聽m_ListenSocket.Close();/關(guān)閉服務(wù)器監(jiān)聽Socketm_ListWords.AddString(監(jiān)聽結(jié)束_);OnAccept()函數(shù)的代碼如下:/ 接收客戶端的連接請求Accept(CChatServe
21、rDlg* )(AfxGetApp()-m_pMainWnd)-m_ServerSocket);(CChatServerDlg* )(AfxGetApp()-m_pMainWnd)-m_ServerSocket.AsyncSelect(FD_READ|FD_CLOSE);(CChatServerDlg* )(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(接收了一個連接);(CChatServerDlg* )(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatServerDlg* )(AfxGe
22、tApp()-m_pMainWnd)-m_ListWords.GetCount() - 1);2.2.2 CAsyncSocket類編程基礎(chǔ)Accept()函數(shù)接收一個套接字的連接請求,從連接請求隊列中取出第一個連接,創(chuàng)建一個與這個套接字具有相同屬性的套接字,并與參數(shù)rConnectedSocket相關(guān)聯(lián),原始的套接字依然保持打開并且偵聽狀態(tài)。函數(shù)原型如下:virtual BOOL Accept(CAsyncSocket& rConnectedSocket, SOCKADDR *lpSockAddr = NULL,int* lpSockAddrlen = NULL);2.2.2 CAsyncS
23、ocket類編程基礎(chǔ)接收客戶連接并創(chuàng)建了對應(yīng)的套接字后,必須調(diào)用AsyncSelect()函數(shù)偵測發(fā)生在該套接字上的網(wǎng)絡(luò)事件,選擇感興趣的網(wǎng)絡(luò)事件來進行處理,表2.3列出了套接字可以偵測到的網(wǎng)絡(luò)事件類型。事 件 標 記事 件FD_READ接收讀準備好的通知FD_WRITE接收寫準備好的通知FD_OOB接收帶外數(shù)據(jù)到達的通知FD_ACCEPT接收等待連接成功的通知FD_CONNECT接收已連接好的通知FD_CLOSE接收套接字關(guān)閉的通知2.2.2 CAsyncSocket類編程基礎(chǔ)OnReceive()函數(shù)代碼(ServerSocket.cpp文件中)如下:/接收客戶端發(fā)來的信息char szT
24、emp200;int n = Receive(szTemp,200);/接收信息szTempn = 0;CString sTemp;sTemp.Format(收到:%s,szTemp);/顯示信息(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(sTemp); (CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex( (CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCou
25、nt() - 1);OnClose()代碼:/關(guān)閉與客戶端的通信信道(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(客戶已斷開);(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount()-1);Close();/關(guān)閉與客戶端通信的Socket2.2.2 CAsyncSocket類編程基礎(chǔ)8運行結(jié)果現(xiàn)在這個程序已
26、經(jīng)具備了最簡單的單向通信功能,客戶端發(fā)送信息服務(wù)器可以收到,運行結(jié)果如圖2.21所示。2.2.2 CAsyncSocket類編程基礎(chǔ)9從單向通信到雙向通信在服務(wù)器界面上添加一個編輯信息的文本框和一個發(fā)送按鈕,如圖2.21所示。2.2.2 CAsyncSocket類編程基礎(chǔ)參照前面的方法,為服務(wù)器的“發(fā)送”按鈕添加與客戶端一樣的事件過程。“發(fā)送”按鈕的事件過程代碼(在ChatServerDlg.cpp中)如下:UpdateData();m_ServerSocket.Send(m_sWords,m_sWords.GetLength();m_ListWords.AddString(發(fā)送: + m_s
27、Words);m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);2.2.2 CAsyncSocket類編程基礎(chǔ)與之對應(yīng),客戶端當(dāng)然也要編寫響應(yīng)函數(shù)用于接收服務(wù)器發(fā)來的信息,于是為客戶端添加OnReceive方法,代碼置于ClientSocket.cpp中。OnReceive()函數(shù)代碼如下:char szTemp200;int n = Receive(szTemp,200);szTempn = 0;CString sTemp;sTemp.Format(收到:%s,szTemp);(CChatClientDlg *)(AfxGetApp()-
28、m_pMainWnd)-m_ListWords.AddString(sTemp);(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex( (CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount() - 1);2.2.2 CAsyncSocket類編程基礎(chǔ)在服務(wù)器界面上安放一個“斷開”按鈕,如圖2.23所示。2.2.2 CAsyncSocket類編程基礎(chǔ)為這個“斷開”按鈕編寫與客戶端“斷開”按鈕一樣的事件過程代碼:m_ServerSocket.C
29、lose();m_ListWords.AddString(與客戶端斷開);這里只不過將調(diào)用Close()函數(shù)的Socket對象由客戶端的m_ClientSocket改成了服務(wù)器的m_ServerSocket,還有就是列表框里的界面狀態(tài)提示信息改成了“與客戶端斷開”,這都無關(guān)緊要。接下來就是一樣的原理,在客戶端添加響應(yīng)網(wǎng)絡(luò)事件的函數(shù)代碼,為客戶端Socket重寫網(wǎng)絡(luò)事件響應(yīng)函數(shù)OnClose,代碼自動置于ClientSocket.cpp中:(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(服務(wù)器斷開了);(CChat
30、ClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount()-1);Close();2.2.2 CAsyncSocket類編程基礎(chǔ)10程序界面的優(yōu)化先在界面上添加一些控件并重新設(shè)計布局,如圖2.24和圖2.25所示。2.2.2 CAsyncSocket類編程基礎(chǔ)各控件關(guān)聯(lián)的變量見表2.4和表2.5。2.2.2 CAsyncSocket類編程基礎(chǔ)1)客戶端在ChatClientDlg.cpp中,BOOL CC
31、hatClientDlg:OnInitDialog()函數(shù)的初始化代碼如下:m_ButtonDisconnect.EnableWindow(false);m_ButtonClear.EnableWindow(false);m_EditWords.EnableWindow(false);m_ButtonSend.EnableWindow(false);“清空”按鈕事件過程代碼如下:m_ListWords.ResetContent();/清空通信狀態(tài)列表中的信息“斷開”按鈕事件過程代碼如下:ServerIP.EnableWindow();ServerPort.EnableWindow();m_Bu
32、ttonConnect.EnableWindow();m_ButtonDisconnect.EnableWindow(false);m_EditWords.EnableWindow(false);m_ButtonSend.EnableWindow(false);m_ButtonExit.EnableWindow();2.2.2 CAsyncSocket類編程基礎(chǔ)“關(guān)于”按鈕事件過程代碼如下:CAboutDlg dlgAbout;dlgAbout.DoModal();/顯示“關(guān)于”對話框在ClientSocket.cpp中,OnConnect()的界面控制代碼如下:(CChatClientDlg
33、*)(AfxGetApp()-m_pMainWnd)-ServerIP.EnableWindow(false);(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-ServerPort.EnableWindow(false);(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonConnect.EnableWindow(false);(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonDisconnect.EnableWindow();(CChatClientDlg*)
34、(AfxGetApp()-m_pMainWnd)-m_EditWords.EnableWindow();(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonSend.EnableWindow();(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonExit.EnableWindow(false);(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonClear.EnableWindow();2.2.2 CAsyncSocket類編程基礎(chǔ)OnClose()
35、中的界面控制代碼如下:(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-ServerIP.EnableWindow();(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-ServerPort.EnableWindow();(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonConnect.EnableWindow();(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonDisconnect.EnableWindow(false)
36、;(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_EditWords.EnableWindow(false);(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ButtonSend.EnableWindow(false);(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ButtonExit.EnableWindow();2.2.2 CAsyncSocket類編程基礎(chǔ)2)服務(wù)器在ChatServerDlg.cpp中,BOOL CChatServerDlg:OnInitDia
37、log()函數(shù)的初始化代碼如下:m_ButtonStopListen.EnableWindow(false);m_ButtonDisconnect.EnableWindow(false);m_ButtonClear.EnableWindow(false);m_EditWords.EnableWindow(false);m_ButtonSend.EnableWindow(false);“開始監(jiān)聽”按鈕事件過程代碼如下:ServerIP.EnableWindow(false);ServerPort.EnableWindow(false);m_ButtonListen.EnableWindow(fa
38、lse);m_ButtonStopListen.EnableWindow();m_ButtonClear.EnableWindow();m_ButtonExit.EnableWindow(false);2.2.2 CAsyncSocket類編程基礎(chǔ)“停止監(jiān)聽”按鈕事件過程代碼如下:ServerIP.EnableWindow();ServerPort.EnableWindow();m_ButtonListen.EnableWindow();m_ButtonStopListen.EnableWindow(false);m_ButtonExit.EnableWindow();“斷開”按鈕事件過程代碼
39、如下:m_ButtonDisconnect.EnableWindow(false);m_EditWords.EnableWindow(false);m_ButtonSend.EnableWindow(false);“清空”按鈕事件過程代碼如下:m_ListWords.ResetContent(); /清空狀態(tài)歷史列表中的信息“關(guān)于”按鈕事件過程代碼如下:CAboutDlg dlgAbout;dlgAbout.DoModal();/顯示“關(guān)于”對話框2.2.2 CAsyncSocket類編程基礎(chǔ)在ListenSocket.cpp中,OnAccept()函數(shù)的界面控制代碼如下:(CChatServ
40、erDlg *)(AfxGetApp()-m_pMainWnd)-m_ButtonDisconnect.EnableWindow();(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_EditWords.EnableWindow();(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ButtonSend.EnableWindow();在ServerSocket.cpp中,OnClose()函數(shù)的界面控制代碼如下:(CchatServerDlg*)(AfxGetApp()-m_pMainWnd)-m_ButtonDi
41、sconnect.EnableWindow(false);(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_EditWords.EnableWindow(false);(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ButtonSend.EnableWindow(false);2.2.2 CAsyncSocket類編程基礎(chǔ)這里截取上面的一小段代碼來舉一個例子,讓讀者對使用EnableWindow函數(shù)控制界面的方法有一個認識。例如,“開始監(jiān)聽”事件過程代碼如下:(1)ServerIP.EnableWindow(fa
42、lse);/使IP地址控件不可用(2)ServerPort.EnableWindow(false);/使端口號固定無法修改(3)m_ButtonListen.EnableWindow(false);/使監(jiān)聽按鈕失效(4)m_ButtonStopListen.EnableWindow();/使用戶可以隨時停止監(jiān)聽(5)m_ButtonClear.EnableWindow();/使清空按鈕生效(6)m_ButtonExit.EnableWindow(false);/使退出按鈕失效2.2.2 CAsyncSocket類編程基礎(chǔ)服務(wù)器程序在用戶按下“開始監(jiān)聽”按鈕前后界面的變化對比如圖2.26所示。2
43、.2.2 CAsyncSocket類編程基礎(chǔ)“關(guān)于”事件過程代碼如下:CAboutDlg dlgAbout;dlgAbout.DoModal();/顯示“關(guān)于”對話框在資源視圖的目錄樹Dialog子目錄下的第一個項目IDD_ABOUTBOX就是“關(guān)于”對話框的ID,雙擊它可以進入 “關(guān)于服務(wù)器”對話框的設(shè)計界面(如圖2.27所示)。2.2.2 CAsyncSocket類編程基礎(chǔ)11程序完全演示分別開啟客戶端程序和服務(wù)器程序(如圖2.28所示)。2.2.2 CAsyncSocket類編程基礎(chǔ)在服務(wù)器輸入IP地址和端口,單擊“開始監(jiān)聽”按鈕,于是服務(wù)器在這個地址上等待客戶端來連接,歷史記錄欄里將自
44、動記下這一事件,如圖2.29所示。2.2.2 CAsyncSocket類編程基礎(chǔ)在客戶端地址欄里輸入與服務(wù)器一樣的IP和端口,單擊“連接”按鈕,連上服務(wù)器,可以看到雙方的狀態(tài)欄里都反映了這次連接的情況(如圖2.30所示)。2.2.2 CAsyncSocket類編程基礎(chǔ)接下來雙方就可以互相通信了,可以互發(fā)信息,信息內(nèi)容會實時自動地顯示在雙方的通信記錄列表中,并且用戶還會發(fā)現(xiàn):當(dāng)某方的通信記錄多到一定量時,列表框會自動以滾動條方式顯示(如圖2.31所示)。2.2.2 CAsyncSocket類編程基礎(chǔ)通信過程中任何一方都可以主動斷開連接(如圖2.32所示)。2.2.2 CAsyncSocket類編
45、程基礎(chǔ)客戶端連接服務(wù)器失敗時會彈出如圖2.33所示的失敗提示。2.2.3 CAsyncSocket類程序的指針實現(xiàn)1非指針程序的機制缺陷歸納起來2.2.2節(jié)的程序存在以下一些編程機制上的缺陷。Socket的創(chuàng)建、使用和銷毀不夠靈活,無法支持很多Socket動態(tài)參與通信過程。程序代碼分散在各個不同的Socket模塊中,不利于統(tǒng)一管理和維護。如果在Socket的代碼中要訪問和控制主對話框界面上的控件,則需要運用AfxGetApp()全局函數(shù)獲取主窗口CWinApp類指針的方法,這意味著每一個在Socket中訪問到主界面控件的語句前都要寫上冗長的類似下面的這句代碼:(CChatClientDlg*)
46、(AfxGetApp()-m_pMainWnd)-2.2.3 CAsyncSocket類程序的指針實現(xiàn)2用對話框指針機制實現(xiàn)的Socket程序1)建立工程。分別創(chuàng)建客戶端和服務(wù)器工程,相關(guān)設(shè)置同2.2.2節(jié),創(chuàng)建完成后在客戶端和服務(wù)器工程中各添加一個基于CAsyncSocket類的MySocket類,如圖2.34所示。這個類是用來給通信雙方動態(tài)生成Socket對象服務(wù)的。2.2.3 CAsyncSocket類程序的指針實現(xiàn)2)用對話框指針機制組織新程序的框架。(1)客戶端。在MySocket.h中添加如下代碼:class CChatClientDlg; /為了能夠在MySocket類中定義主對
47、話框類指針,首先對主對話框類進行前導(dǎo)聲明CChatClientDlg * m_dlg; /在MySocket類中定義一個主對話框指針void GetDlg(CChatClientDlg * dlg); /獲取主對話框指針的函數(shù)2.2.3 CAsyncSocket類程序的指針實現(xiàn)代碼添加位置如圖2.35所示。2.2.3 CAsyncSocket類程序的指針實現(xiàn)在ChatClientDlg.h中添加如下代碼:#include MySocket.h /引用MySocket類的頭文件,為下面定義一個MySocket類對象指針MySocket * m_ClientSocket;/定義一個MySocket
48、類對象指針,用于動態(tài)生成客戶Socketvoid OnReceive();void OnClose();void OnConnect(); /一會兒要在主對話框代碼中實現(xiàn)這三個函數(shù)的功能void SocketReset(); /套接字重置銷毀函數(shù),及時清理不再使用的Socket,避免指針懸空2.2.3 CAsyncSocket類程序的指針實現(xiàn)在ChatClientDlg.cpp中將MySocket類對象指針初始化為空,如圖2.36所示。2.2.3 CAsyncSocket類程序的指針實現(xiàn)寫出已聲明的三個函數(shù)OnClose()、OnConnect()、OnReceive()的函數(shù)體,同時實現(xiàn)So
49、cketReset()函數(shù),代碼如下:void CChatClientDlg:SocketReset()/SocketReset函數(shù)實現(xiàn) if(m_ClientSocket!=NULL) delete m_ClientSocket;m_ClientSocket=NULL; 2.2.3 CAsyncSocket類程序的指針實現(xiàn)在MySocket.cpp中實現(xiàn)獲取主對話框指針的GetDlg()函數(shù),并通過指針引用主對話框程序代碼中的網(wǎng)絡(luò)事件處理函數(shù),代碼如下:#include ChatClientDlg.hvoid MySocket:GetDlg(CChatClientDlg * dlg) /獲得
50、窗口界面的指針 m_dlg=dlg; void MySocket:OnClose(int nErrorCode) / TODO: Add your specialized code here and/or call the base class m_dlg-OnClose(); CAsyncSocket:OnClose(nErrorCode);void MySocket:OnConnect(int nErrorCode) / TODO: Add your specialized code here and/or call the base class m_dlg-OnConnect(); CA
51、syncSocket:OnConnect(nErrorCode);void MySocket:OnReceive(int nErrorCode) / TODO: Add your specialized code here and/or call the base classm_dlg-OnReceive();CAsyncSocket:OnReceive(nErrorCode);2.2.3 CAsyncSocket類程序的指針實現(xiàn)采用與客戶端類似的方法,在MySocket.h中添加如下代碼:class CChatServerDlg;/首先對主對話框類進行前導(dǎo)聲明CChatServerDlg *
52、 m_dlg;/定義主對話框指針void GetDlg(CChatServerDlg * dlg); /指針獲取函數(shù)與客戶端一樣,系統(tǒng)自動為每個函數(shù)生成函數(shù)聲明和函數(shù)體框架,另外,在ChatServerDlg.cpp中將MySocket類對象指針初始化為空。#include MySocket.h /引用MySocket類頭文件,為后面定義動態(tài)Socket對象指針MySocket * m_ServerSocket; /MySocket類對象指針,用于動態(tài)生成與客戶通信的SocketMySocket * m_ListenSocket; /定義MySocket類對象指針,用于動態(tài)生成監(jiān)聽Socket
53、void OnReceive();void OnClose();void OnAccept(); /要在主對話框代碼中實現(xiàn)的服務(wù)器功能的三個函數(shù)void SocketReset(); /重置銷毀不再使用的套接字2.2.3 CAsyncSocket類程序的指針實現(xiàn)在ChatServerDlg.cpp中寫出OnAccept()、OnClose()、OnReceive()三個函數(shù)的函數(shù)體,為它們的實現(xiàn)代碼預(yù)留出空間,同時實現(xiàn)SocketReset函數(shù),代碼如下:void CChatServerDlg:SocketReset() /SocketReset函數(shù)實現(xiàn) if(m_ServerSocket !
54、= NULL)delete m_ServerSocket; /在此要銷毀兩個Socket,一個是與客戶端通信的Socketm_ServerSocket = NULL; if(m_ListenSocket != NULL)delete m_ListenSocket;/還有一個是監(jiān)聽Socketm_ListenSocket = NULL;2.2.3 CAsyncSocket類程序的指針實現(xiàn)在MySocket.cpp中實現(xiàn)獲取主對話框指針的GetDlg()函數(shù),并通過指針引用主對話框的三個函數(shù):#include ChatServerDlg.hvoid MySocket:GetDlg(CChatSer
55、verDlg *dlg) /獲得窗口界面的指針m_dlg = dlg; void MySocket:OnClose(int nErrorCode) /TODO: 在此添加專用代碼和/或調(diào)用基類 m_dlg-OnClose(); CAsyncSocket:OnClose(nErrorCode);void MySocket:OnReceive(int nErrorCode) /TODO: 在此添加專用代碼和/或調(diào)用基類 m_dlg-OnReceive(); CAsyncSocket:OnReceive(nErrorCode);void MySocket:OnAccept(int nErrorCod
56、e) /TODO: 在此添加專用代碼和/或調(diào)用基類if(m_dlg-m_ServerSocket = NULL)m_dlg-OnAccept(); CAsyncSocket:OnAccept(nErrorCode); 2.2.3 CAsyncSocket類程序的指針實現(xiàn)3)代碼的復(fù)制、修改。(1)客戶端。“連接”按鈕事件過程代碼如下:/初始化套接字,獲取對話框指針if(!AfxSocketInit()MessageBox(WindowSocket initial failed!,Receive,MB_ICONSTOP);return;m_ClientSocket = new MySocket;
57、m_ClientSocket-GetDlg(this);/連接服務(wù)器BYTE nFild4;CString sIP;UpdateData();ServerIP.GetAddress(nFild0,nFild1,nFild2,nFild3);sIP.Format(%d.%d.%d.%d,nFild0,nFild1,nFild2,nFild3);m_ClientSocket-Create();/創(chuàng)建客戶端Socketm_ClientSocket-Connect(sIP,sPort);/發(fā)起連接請求2.2.3 CAsyncSocket類程序的指針實現(xiàn)“斷開”按鈕事件過程代碼如下:/斷開與服務(wù)器的連接
58、m_ClientSocket-Close();/關(guān)閉客戶端SocketSocketReset(); /避免指針懸空m_ListWords.AddString(從服務(wù)器斷開);/界面完善m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);ServerIP.EnableWindow();ServerPort.EnableWindow();m_ButtonConnect.EnableWindow();m_ButtonDisconnect.EnableWindow(false);m_EditWords.EnableWindow(false);m_Bu
59、ttonSend.EnableWindow(false);m_ButtonExit.EnableWindow();“發(fā)送”按鈕事件過程代碼如下:UpdateData();m_ClientSocket-Send(m_sWords,m_sWords.GetLength();/向服務(wù)器發(fā)送信息m_ListWords.AddString(發(fā)送: + m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);2.2.3 CAsyncSocket類程序的指針實現(xiàn)OnClose()函數(shù)代碼如下:m_ListWords.AddString(服務(wù)
60、器斷開了);m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);m_ClientSocket-Close();SocketReset();/避免指針懸空/界面完善ServerIP.EnableWindow();ServerPort.EnableWindow();m_ButtonConnect.EnableWindow();m_ButtonDisconnect.EnableWindow(false);m_EditWords.EnableWindow(false);m_ButtonSend.EnableWindow(false);m_Button
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 股東權(quán)益分配指南
- 建筑工程地面施工合同
- 全球旅游業(yè)市場規(guī)模變化報告表
- 個人月度財務(wù)收支記錄表
- 三農(nóng)村園林綠化工程建設(shè)實施方案
- 2025年安徽體育運動職業(yè)技術(shù)學(xué)院單招職業(yè)傾向性考試題庫及參考答案一套
- 交通監(jiān)控設(shè)備使用說明
- 三農(nóng)村信用制度創(chuàng)新與實踐方案
- 二手摩托車買賣合同
- 廣州手房交易合同
- 新教科版五下科學(xué)1-5《當(dāng)環(huán)境改變了》公開課課件
- 教師的十大轉(zhuǎn)變課件
- 焦化廠生產(chǎn)工序及工藝流程圖
- 可下載打印的公司章程
- 中藥熏洗法課件
- 本特利探頭應(yīng)用
- 城市雕塑藝術(shù)工程工程量計價清單定額2022年版
- QMR-110-00員工手部、接觸面等微生物檢驗記錄記錄
- 外陰及陰道炎癥
- 公安筆錄模板之詢問嫌疑人(書面?zhèn)鲉局伟舶讣?
- A-level項目介紹(課堂PPT)
評論
0/150
提交評論