




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第2章MFCSocket編程2.1
MFC及其Socket類2.2
C/S模式下網(wǎng)絡(luò)程序的Socket通信實例2.3
與第三方程序的互通及Socket編程的本質(zhì)2.1MFC及其Socket類2.1.1MFC簡介MFC,微軟根底類〔Microsoft
Foundation
Classes〕,同VCL類似,是一種應(yīng)用框架〔ApplicationFramework〕,隨微軟VisualC++開發(fā)工具發(fā)布。MFC是很龐大的,如最新版本中包含了大約兩百多個不同的類〔如圖2.1所示〕。2.1.1MFC簡介2.1.2MFC中的Socket類1.CAsyncSocket類CAsyncSocket類是從MFC的根類CObject派生出來的,它在較低的級別上封裝WindowsSocketAPI。CAsyncSocket類在MFC套接字類中的繼承位置如圖2.2所示。CAsyncSocket類的成員函數(shù)如表2.1所示。2.1.2MFC中的Socket類2.CSocket類及其相關(guān)類〔1〕CSocket類。CSocket類是從CAsyncSocket派生而來的,它繼承了CAsyncSocket對WindowsSocketAPI的封裝?!?〕CSocket與CArchive、CSocketFile類的配合使用。用CSocket類編寫網(wǎng)絡(luò)程序,既可以使用如CAsyncSocket類網(wǎng)絡(luò)程序一樣的Send和Receive函數(shù)來收發(fā)信息,也可以與CSocketFile類和CArchive類一起來管理對數(shù)據(jù)的發(fā)送和接收。
2.2C/S模式下網(wǎng)絡(luò)程序的Socket通信實例2.2.1客戶—效勞器方式〔C/S模式〕1.網(wǎng)絡(luò)軟件的通用體系結(jié)構(gòu)客戶〔Client〕和效勞器〔Server〕是指通信中所涉及的兩個應(yīng)用進(jìn)程??蛻簟谄鞣绞剿枋龅氖沁M(jìn)程之間效勞和被效勞的關(guān)系。在圖2.3中,主機(jī)A運行客戶程序而主機(jī)B運行效勞器程序。2.2.1客戶—效勞器方式〔C/S模式〕2.最簡單的Socket通信流程一個只有客戶方向效勞方發(fā)信息的單向通信,并且也只有客戶方會主動提出斷開連接的最簡單的情形〔相反過程的原理是一樣的〕,其雙方Socket之間的關(guān)系如圖2.4所示。2.2.1客戶—效勞器方式〔C/S模式〕由上面這個十分簡單的過程很容易得出最簡單的Socket通信流程,如圖2.5所示。2.2.2CAsyncSocket類編程根底1.對象分析由節(jié)分析的最簡單的Socket通信流程可見,要實現(xiàn)這樣一個完整流程需要三個套接字對象:客戶端一個〔我們稱為“客戶Socket”〕,效勞器端兩個〔一個用于監(jiān)聽,稱為“監(jiān)聽Socket”;另一個用于接收客戶發(fā)來的信息,稱為“效勞Socket”〕,這三個套接字對象對應(yīng)三個Socket類,都繼承自CAsyncSocket,分別給它們?nèi)∶绫?.2所示。Socket對象類名客戶SocketCClientSocket監(jiān)聽SocketCListenSocket服務(wù)SocketCServerSocket2.2.2CAsyncSocket類編程根底2.創(chuàng)立工程和套接字對象首先創(chuàng)立客戶端工程。翻開VisualStudio2008環(huán)境,建立一個新的基于對話框的MFC工程,工程名稱為ChatClient,接著一直單擊“下一步”按鈕,直到設(shè)置程序“高級功能”對話框,如圖2.6所示。2.2.2CAsyncSocket類編程根底創(chuàng)立類名為CClientSocket的客戶Socket對象,下面給工程添加類,選擇菜單命令“工程”→“添加類”,如圖2.7所示。2.2.2CAsyncSocket類編程根底在彈出的“添加類”對話框中選擇“MFC類”項,單擊“添加”按鈕〔如圖2.8所示〕。2.2.2CAsyncSocket類編程根底在“MFC類向?qū)А睂υ捒蛑休斎腩惷鸆ClientSocket,向?qū)⒆詣訛檫@個添加的類生成名為“ClientSocket.h”和“ClientSocket.cpp”的頭文件和源文件,如圖2.9所示。2.2.2CAsyncSocket類編程根底單擊“完成”按鈕,可以在類視圖中看到剛剛添加的類CClientSocket〔如圖2.10所示〕。2.2.2CAsyncSocket類編程根底3.理清程序文件的組織結(jié)構(gòu)〔1〕客戶端程序文件。翻開已經(jīng)創(chuàng)立好的客戶端工程,在解決方案資源管理器中可以看到工程的所有程序文件〔如圖2.11所示〕。2.2.2CAsyncSocket類編程根底全部程序文件可以分成三類:第一類是.h后綴的頭文件,用來集中聲明定義程序中用到的類、變量、函數(shù)、宏等;第二類是.cpp后綴的源文件,這是程序代碼的主體,集中存放程序的源代碼;第三類是資源文件,存放程序中用到的資源,如圖標(biāo)、圖像、音頻、視頻等,2.2.2CAsyncSocket類編程根底〔2〕效勞器端的源文件。同理,效勞器端也對應(yīng)這幾種程序文件,翻開效勞器工程,可以看到它們〔如圖2.12所示〕。2.2.2CAsyncSocket類編程根底4.用頭文件和類對象將程序源文件聯(lián)成有機(jī)整體例如,已經(jīng)創(chuàng)立了各個Socket對象并且也有了它們各自對應(yīng)的程序文件,但這些文件仍然是孤立的,相互之間的代碼無法訪問,要使它們能聯(lián)系在一起,使控制程序的主文件能夠自如地操縱Socket,就必須通過頭文件聲明和創(chuàng)立類對象成員變量將各個類聯(lián)成有機(jī)的整體。要使客戶端程序能夠創(chuàng)立和控制本地的Socket,在客戶端工程界面控制模塊的頭文件ChatClientDlg.h中添加如下兩行代碼:#include"ClientSocket.h" //使主界面程序能夠訪問Socket類的代碼文件CClientSocketm_ClientSocket;//為了后面與效勞器通信而定義的Socket成員變量2.2.2CAsyncSocket類編程根底以上兩行代碼的添加位置如圖2.13所示中“//ADD”記號之間標(biāo)出的局部。2.2.2CAsyncSocket類編程根底反過來要使Socket能夠訪問到主界面上的控件,以便能夠?qū)⒆约旱臓顩r隨時反映給主程序并在主界面上顯示出來,也需要在Socket源文件ClientSocket.cpp中添加頭文件聲明:#include"ChatClientDlg.h"同理,要使效勞端程序能夠創(chuàng)立和控制本地的Socket,也要在效勞端工程界面控制模塊的頭文件ChatServerDlg.h中添加如下代碼:#include"ListenSocket.h" //使主界面程序能夠訪問監(jiān)聽Socket類的代碼文件#include"ServerSocket.h" //使主界面程序能夠訪問效勞Socket類的代碼文件CServerSocketm_ServerSocket; //為了后面與客戶通信而定義的Socket成員變量CListenSocketm_ListenSocket; //為了監(jiān)聽客戶端的連接請求而定義的Socket成員變量2.2.2CAsyncSocket類編程根底以上四行代碼的添加位置如圖2.14所示中“//ADD”記號之間標(biāo)出的局部。2.2.2CAsyncSocket類編程根底5.布局簡潔的界面在客戶端“資源視圖”展開的目錄樹下雙擊Dialog文件夾下第二個工程,轉(zhuǎn)到用戶界面設(shè)計工作區(qū)〔如圖2.15所示〕。2.2.2CAsyncSocket類編程根底完成的客戶端簡化界面〔如圖2.16所示〕上,包括IP地址控件、列表框各1個,文本框兩個,四個按鈕。2.2.2CAsyncSocket類編程根底用相同的方法設(shè)置效勞器端的用戶界面如圖2.17所示,也一樣為IP地址控件關(guān)聯(lián)變量ServerIP,為文本框控件關(guān)聯(lián)int型變量sPort,為列表框關(guān)聯(lián)變量m_ListWords。2.2.2CAsyncSocket類編程根底6.雛形程序試運行到此為止,這個程序的雛形已經(jīng)形成,分別運行客戶和效勞器端的工程如圖2.18所示。2.2.2CAsyncSocket類編程根底7.程序代碼的組織接下來就要為這個程序雛形注入靈性,添加核心源代碼了。在此之前,先來回憶一下前面設(shè)計的那個最簡單的Socket通信流程,如圖2.19所示。2.2.2CAsyncSocket類編程根底從上面已經(jīng)標(biāo)注了所用函數(shù)的通信流程圖,可以進(jìn)一步得出下面的源程序代碼組織框圖〔如圖2.20所示〕。2.2.2CAsyncSocket類編程根底8.源代碼完全剖析〔1〕客戶端源碼??蛻舳擞脩羰紫戎鲃影l(fā)起連接,以下是“連接”按鈕的事件過程,位于ChatClientDlg.cpp文件中://連接效勞器BYTEnFild[4];CStringsIP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);m_ClientSocket.Create(); //創(chuàng)立客戶端Socketm_ClientSocket.Connect(sIP,sPort); //發(fā)起連接請求2.2.2CAsyncSocket類編程根底Create()函數(shù)用來創(chuàng)立和初始化套接字,具體過程為:構(gòu)造套接字對象m_ClientSocket后,調(diào)用Create()成員函數(shù)創(chuàng)立Socket句柄,并調(diào)用Bind()成員函數(shù)將其與指定的地址綁定,Create()函數(shù)原型為:BOOLCreate(UINTnSocketport=0,intnSocketType=SOCK_STREAM,longlEvent=FD_READ︱FD_WRITE︱FD_OOB︱FD_ACCEPT︱FD_CONNECT︱FD_CLOSE,LPCTSTRlpszSocketaddress=NULL);Connect()函數(shù)用于未連接的數(shù)據(jù)流或者數(shù)據(jù)報套接字建立連接。其函數(shù)原型為:BOOLConnect(LPCTSTRlpszHostAddress,UINTnHostPort);BOOLConnect(constSOCKADDR*lpSockAddr,intnSockAddrLen);2.2.2CAsyncSocket類編程根底客戶端也可以隨時主動斷開通信連接,下面是“斷開”按鈕的事件過程://斷開與效勞器的連接m_ClientSocket.Close(); //關(guān)閉客戶端Socketm_ListWords.AddString("從效勞器斷開");Close()函數(shù)用來關(guān)閉套接字并釋放Socket描述符,其函數(shù)原型為:virtualvoidClose();客戶端可以向效勞器發(fā)送信息,“發(fā)送”按鈕的事件過程為://向效勞器發(fā)信息UpdateData();m_ClientSocket.Send(m_sWords,m_sWords.GetLength()); //發(fā)信息m_ListWords.AddString("發(fā)送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);Send()函數(shù)通過數(shù)據(jù)報或者數(shù)據(jù)流向?qū)Ψ教捉幼职l(fā)送數(shù)據(jù),其函數(shù)原型為:virtualintSend(constvoid*lpBuf,intnBufLen,intnFlags=0);2.2.2CAsyncSocket類編程根底在類視圖中選中CClientSocket,在界面右下角的屬性窗口中單擊“重寫”按鈕,就可以為該Socket類編寫被動響應(yīng)網(wǎng)絡(luò)事件的函數(shù)〔如圖2.21所示〕。2.2.2CAsyncSocket類編程根底選擇OnConnect()函數(shù),為其添加代碼,系統(tǒng)將該函數(shù)的代碼自動置于ClientSocket.cpp文件中。OnConnect()函數(shù)代碼如下://確認(rèn)客戶端是否成功連接到效勞器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.2CAsyncSocket類編程根底〔2〕效勞器端源碼〔ChatServerDlg.cpp文件中〕?!伴_始監(jiān)聽”按鈕的事件過程如下://監(jiān)聽開始,效勞器等待連接請求的到來BYTEnFild[4];CStringsIP,sP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);sP.Format("%d",sPort);m_ListenSocket.Create(sPort,1,FD_ACCEPT,sIP); //創(chuàng)立效勞端監(jiān)聽Socketm_ListenSocket.Listen(1); //開始監(jiān)聽m_ListWords.AddString("監(jiān)聽開始:");m_ListWords.AddString("地址"+sIP+"端口"+sP);m_ListWords.AddString("等待客戶端連接……");Listen()函數(shù)用于偵聽連接請求,原型為:BOOLListen(intnConnectionBackloh=5);2.2.2CAsyncSocket類編程根底Accept()函數(shù)接受一個套接字的連接請求,從連接請求隊列中取出第一個連接,創(chuàng)立一個與這個套接字具有相同屬性的套接字,并與參數(shù)rConnectedSocket相關(guān)聯(lián),原始的套接字依然保持翻開并且偵聽狀態(tài)。函數(shù)原型為:virtualBOOLAccept(CAsyncSocket&rConnectedSocket,SOCKADDR*lpSockAddr=NULL,int*lpSockAddrlen=NULL);2.2.2CAsyncSocket類編程根底表2.3列出了套接字可以偵測到的網(wǎng)絡(luò)事件類型。事件標(biāo)記事件FD_READ接收讀準(zhǔn)備好的通知FD_WRITE接收寫準(zhǔn)備好的通知FD_OOB接收帶外數(shù)據(jù)到達(dá)的通知FD_ACCEPT接收等待連接成功的通知FD_CONNECT接收已連接好的通知FD_CLOSE接收套接字關(guān)閉的通知2.2.2CAsyncSocket類編程根底OnReceive()函數(shù)代碼〔ServerSocket.cpp文件中〕:
//接收客戶端發(fā)來的信息charszTemp[200];intn=Receive(szTemp,200); //接收信息szTemp[n]='\0';CStringsTemp;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.GetCount()-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.2CAsyncSocket類編程根底9.運行結(jié)果現(xiàn)在這個程序已經(jīng)具備了最簡單的單向通信功能,客戶端發(fā)出信息效勞器端可以收到,運行結(jié)果如圖2.22所示。2.2.2CAsyncSocket類編程根底10.從單向通信到雙向交流下面就來添加效勞端到客戶端的通信功能。先在效勞器界面上添加一個編輯信息的文本框和一個發(fā)送按鈕,如圖2.23所示。2.2.2CAsyncSocket類編程根底效勞器的“發(fā)送”按鈕添加與客戶端的一樣的事件過程?!鞍l(fā)送”按鈕的事件過程代碼〔在ChatServerDlg.cpp中〕如下:UpdateData();m_ServerSocket.Send(m_sWords,m_sWords.GetLength());m_ListWords.AddString("發(fā)送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);是為客戶端添加OnReceive方法,代碼置于ClientSocket.cpp中。OnReceive()函數(shù)代碼如下:charszTemp[200];intn=Receive(szTemp,200);szTemp[n]='\0';CStringsTemp;sTemp.Format("收到:%s",szTemp);((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString(sTemp);((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex( ((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);
2.2.2CAsyncSocket類編程根底參照客戶端斷開連接的原理,在效勞器界面上安放一個“斷開”按鈕〔如圖2.24所示〕。2.2.2CAsyncSocket類編程根底為這個“斷開”按鈕編寫與客戶端“斷開”按鈕一樣的事件過程代碼:m_ServerSocket.Close();m_ListWords.AddString("與客戶端斷開");下來就是一樣的原理,在客戶端添加響應(yīng)網(wǎng)絡(luò)事件的函數(shù)代碼,為客戶端Socket重寫網(wǎng)絡(luò)事件響應(yīng)函數(shù)OnClose,代碼自動置于ClientSocket.cpp中:((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("效勞器端斷開了");((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);Close();2.2.2CAsyncSocket類編程根底運行后界面如圖2.25所示。2.2.2CAsyncSocket類編程根底11.程序界面的優(yōu)化和控制先在界面上添加一些控件并重新設(shè)計布局如圖2.26和圖2.27所示。2.2.2CAsyncSocket類編程根底各控件關(guān)聯(lián)的變量見表2.4和表2.5??丶兞浚ò愋停㊣P地址控件contrlServerIP“端口”編輯框contrlServerPort;intsPort“連接”按鈕contrlm_ButtonConnect“斷開”按鈕contrlm_ButtonDisconnect列表框contrlm_ListWords“清空”按鈕contrlm_ButtonClear發(fā)送信息編輯框contrlm_EditWords;CStringm_sWords“發(fā)送”按鈕contrlm_ButtonSend“退出”按鈕contrlm_ButtonExit控件變量(包括類型)IP地址控件contrlServerIP“端口”編輯框contrlServerPort;intsPort列表框contrlm_ListWords“斷開”按鈕contrlm_ButtonDisconnect“清空”按鈕contrlm_ButtonClear“退出”按鈕contrlm_ButtonExit“開始監(jiān)聽”按鈕contrlm_ButtonListen“停止監(jiān)聽”按鈕contrlm_ButtonStopListen發(fā)送信息編輯框contrlm_EditWords;CStringm_sWords“發(fā)送”按鈕contrlm_ButtonSend2.2.2CAsyncSocket類編程根底截取上面的一小段代碼來舉一個例子讓讀者對使用EnableWindow函數(shù)控制界面的方法有個感性認(rèn)識。例如:“開始監(jiān)聽”事件過程代碼如下:(1) ServerIP.EnableWindow(false); //使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.2CAsyncSocket類編程根底效勞器端程序在用戶按下“開始監(jiān)聽”按鈕前后界面的變化比照方圖2.28所示。
2.2.2CAsyncSocket類編程根底“關(guān)于”事件過程代碼如下: CAboutDlgdlgAbout; dlgAbout.DoModal(); //顯示“關(guān)于”對話框在資源視圖的目錄樹Dialog子目錄下的第一個工程IDD_ABOUTBOX就是“關(guān)于”對話框的ID,雙擊它可以進(jìn)入“關(guān)于”對話框的設(shè)計界面〔如圖2.29所示〕。2.2.2CAsyncSocket類編程根底在此,用戶可以設(shè)計“關(guān)于”對話框的外觀,寫上版權(quán)聲明。在這個例子中,簡單地設(shè)計雙方通信軟件的“關(guān)于”對話框如圖2.30所示。2.2.2CAsyncSocket類編程根底12.程序完全演示分別開啟客戶端程序和效勞器端程序〔如圖2.31所示〕。2.2.2CAsyncSocket類編程根底在效勞器端輸入IP地址和端口,單擊“開始監(jiān)聽”按鈕,效勞器于是在這個地址上等待客戶來連接,歷史記錄欄里將自動記下這一事件,如圖2.32所示。2.2.2CAsyncSocket類編程根底在客戶端地址欄里輸入和效勞器一樣的IP和端口,單擊“連接”按鈕,連上效勞器,可以看到雙方的狀態(tài)欄里都反映了這次連接的情況〔如圖2.33所示〕。2.2.2CAsyncSocket類編程根底接下來雙方就可以互相通信了,可以互發(fā)信息,信息內(nèi)容會實時自動地顯示在雙方的通信記錄列表中,并且你還會發(fā)現(xiàn):當(dāng)某方的通信記錄多到一定量時,列表框會自動以滾動條方式顯示〔如圖2.34所示〕。2.2.2CAsyncSocket類編程根底通信過程中任何一方都可以主動斷開連接〔如圖2.35所示〕。2.2.2CAsyncSocket類編程根底也可以重新連接,并隨時清空通信記錄〔如圖2.36所示〕。2.2.2CAsyncSocket類編程根底單擊“關(guān)于”按鈕,查看版權(quán)信息〔如圖2.37所示〕。2.2.2CAsyncSocket類編程根底效勞器隨時可以停止監(jiān)聽,客戶端連接效勞器失敗時會彈出失敗提示〔如圖2.38所示〕。2.2.3CAsyncSocket類程序的指針實現(xiàn)1.傳統(tǒng)程序機(jī)制的弊端歸納起來節(jié)的程序存在以下一些編程機(jī)制上的弊端:〔1〕Socket的創(chuàng)立、使用和銷毀不夠靈活,無法支持很多Socket動態(tài)參與通信過程的情況?!?〕程序代碼分散在各個不同的Socket模塊中,不利于統(tǒng)一管理和維護(hù)?!?〕如果在Socket的代碼中要訪問和控制主對話框界面上的控件,那么需要運用AfxGetApp()全局函數(shù)獲取主窗口CWinApp類指針的方法,這意味著每一個在Socket中訪問到主對話框界面上控件的語句前都要寫上冗長的類似下面的這句代碼:((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->2.2.3CAsyncSocket類程序的指針實現(xiàn)2.用對話框指針機(jī)制實現(xiàn)的Socket程序〔1〕創(chuàng)立工程、添加類、用戶界面。創(chuàng)立完成后在客戶和效勞器端工程中各添加一個基于CAsyncSocket類的MySocket類,它是用來給通信雙方動態(tài)生成Socket對象使用的,如圖2.39所示。2.2.3CAsyncSocket類程序的指針實現(xiàn)參照上節(jié)例子程序給這個程序設(shè)計個一模一樣的界面,如圖2.40所示。2.2.3CAsyncSocket類程序的指針實現(xiàn)〔2〕用對話框指針機(jī)制組織新的程序雛形??蛻舳?。代碼添加位置如圖2.41所示。2.2.3CAsyncSocket類程序的指針實現(xiàn)給MySocket類添加網(wǎng)絡(luò)事件處理函數(shù),在這里我們添加OnClose()、OnConnect()、OnReceive()三個函數(shù),分別用于響應(yīng)效勞器斷開連接事件、客戶發(fā)起連接請求事件、接收到效勞器發(fā)來的數(shù)據(jù),系統(tǒng)將自動為每個函數(shù)生成函數(shù)聲明和函數(shù)體的框架,如圖2.42所示。2.2.3CAsyncSocket類程序的指針實現(xiàn)在ChatClientDlg.cpp中將MySocket類對象指針初始化為空,并寫出我們上面已聲明的三個函數(shù)OnClose()、OnConnect()、OnReceive()的函數(shù)體,為它們的實現(xiàn)代碼預(yù)留出空間〔如圖2.43所示〕,同時實現(xiàn)SocketReset()函數(shù),代碼如下:voidCChatClientDlg::SocketReset() //SocketReset函數(shù)實現(xiàn){ if(m_ClientSocket!=NULL) { deletem_ClientSocket; m_ClientSocket=NULL; }}2.2.3CAsyncSocket類程序的指針實現(xiàn)2.2.3CAsyncSocket類程序的指針實現(xiàn)效勞端。采用與客戶端類似的方法,在MySocket.h中添加: classCChatServerDlg; //先對主對話框類進(jìn)行前導(dǎo)聲明 CChatServerDlg*m_dlg; //定義主對話框指針 voidGetDlg(CChatServerDlg*dlg); //指針獲取函數(shù)與客戶端一樣,系統(tǒng)自動為每個函數(shù)生成函數(shù)聲明和函數(shù)體框架,另外我們在ChatServerDlg.cpp中將MySocket類對象指針初始化為空。#include"MySocket.h"http://引用MySocket類頭文件,為了后面定義動態(tài)Socket對象指針MySocket*m_ServerSocket;//MySocket類對象指針,用于動態(tài)生成與客戶通信的 //SocketMySocket*m_ListenSocket;//定義MySocket類對象指針,用于動態(tài)生成監(jiān)聽SocketvoidOnReceive();voidOnClose();voidOnAccept(); //要在主對話框代碼中實現(xiàn)的效勞器端功能的三個函數(shù)voidSocketReset(); //重置銷毀不再使用的套接字2.2.3CAsyncSocket類程序的指針實現(xiàn)在ChatServerDlg.cpp中寫出OnAccept()、OnClose()、OnReceive()三個函數(shù)的函數(shù)體,為它們的實現(xiàn)代碼預(yù)留出空間,同時實現(xiàn)SocketReset函數(shù),代碼如下:voidCChatServerDlg::SocketReset() //SocketReset函數(shù)實現(xiàn){ if(m_ServerSocket!=NULL) { deletem_ServerSocket; //在此要銷毀兩個Socket,一個是與客戶通
//信的Socket m_ServerSocket=NULL; } if(m_ListenSocket!=NULL) { deletem_ListenSocket; //還有一個是監(jiān)聽Socket m_ListenSocket=NULL; }}2.2.3CAsyncSocket類程序的指針實現(xiàn)試運行的界面如圖2.44所示。2.2.3CAsyncSocket類程序的指針實現(xiàn)〔3〕代碼的復(fù)制、修改??蛻舳恕!斑B接”按鈕事件過程代碼如下://初始化套接字,獲取對話框指針if(!AfxSocketInit()){ MessageBox("WindowSocketinitialfailed!","Receive",MB_ICONSTOP); return;}m_ClientSocket=newMySocket;m_ClientSocket->GetDlg(this);//連接效勞器BYTEnFild[4];CStringsIP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);m_ClientSocket->Create(); //創(chuàng)立客戶端Socketm_ClientSocket->Connect(sIP,sPort); //發(fā)起連接請求2.2.3CAsyncSocket類程序的指針實現(xiàn)“斷開”按鈕事件過程代碼如下://斷開與效勞器的連接m_ClientSocket->Close(); //關(guān)閉客戶端SocketSocketReset(); //防止指針懸空m_ListWords.AddString("從效勞器斷開");“發(fā)送”按鈕事件過程代碼如下:UpdateData();m_ClientSocket->Send(m_sWords,m_sWords.GetLength());//向效勞器發(fā)送信息m_ListWords.AddString("發(fā)送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket類程序的指針實現(xiàn)OnClose()函數(shù)代碼如下:m_ListWords.AddString("效勞器端斷開了");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);m_ClientSocket->Close();SocketReset(); //防止指針懸空OnReceive()函數(shù)代碼如下:charszTemp[200];intn=m_ClientSocket->Receive(szTemp,200);szTemp[n]='\0';CStringsTemp;sTemp.Format("收到:%s",szTemp);m_ListWords.AddString(sTemp);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);OnConnect()函數(shù)代碼如下:m_ListWords.AddString("連接效勞器成功!");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket類程序的指針實現(xiàn)效勞器端。“開始監(jiān)聽”按鈕事件過程代碼如下://初始化套接字,獲取對話框指針if(!AfxSocketInit()){ MessageBox("WindowSocketinitialfailed!","Send",MB_ICONSTOP); return;}m_ListenSocket=newMySocket;m_ListenSocket->GetDlg(this);//監(jiān)聽開始,效勞器等待連接請求的到來BYTEnFild[4];CStringsIP,sP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);sP.Format("%d",sPort);m_ListenSocket->Create(sPort,1,FD_ACCEPT,sIP); //創(chuàng)立效勞端監(jiān)聽Socketm_ListenSocket->Listen(1); //開始監(jiān)聽m_ListWords.AddString("監(jiān)聽開始:");m_ListWords.AddString("地址"+sIP+"端口"+sP);m_ListWords.AddString("等待客戶端連接……");2.2.3CAsyncSocket類程序的指針實現(xiàn)“停止監(jiān)聽”按鈕事件過程代碼如下://停止監(jiān)聽m_ListenSocket->Close(); //關(guān)閉效勞端監(jiān)聽Socketif(m_ListenSocket!=NULL) //防止指針懸空{(diào) deletem_ListenSocket; m_ListenSocket=NULL;}m_ListWords.AddString("停止監(jiān)聽");“斷開”按鈕的事件過程代碼如下:m_ServerSocket->Close();if(m_ServerSocket!=NULL){ deletem_ServerSocket; m_ServerSocket=NULL;}m_ListWords.AddString("與客戶端斷開");2.2.3CAsyncSocket類程序的指針實現(xiàn)“發(fā)送”按鈕的事件過程代碼如下:UpdateData();m_ServerSocket->Send(m_sWords,m_sWords.GetLength());//獲取文本長度m_ListWords.AddString("發(fā)送:"+m_sWords); //顯示發(fā)送文件長度m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);OnAccept()函數(shù)代碼如下://動態(tài)創(chuàng)立用于通信的Socketm_ServerSocket=newMySocket;m_ServerSocket->GetDlg(this);//接受客戶端的連接請求m_ListenSocket->Accept(*m_ServerSocket); //接受連接請求m_ServerSocket->AsyncSelect(FD_READ|FD_CLOSE);m_ListWords.AddString("接受了一個客戶端的連接請求");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket類程序的指針實現(xiàn)OnClose()函數(shù)代碼如下://關(guān)閉與客戶端的通信信道m(xù)_ListWords.AddString("客戶端斷開連接");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);m_ServerSocket->Close(); //關(guān)閉與客戶端通信的Socketif(m_ServerSocket!=NULL){ deletem_ServerSocket; m_ServerSocket=NULL;}OnReceive()函數(shù)代碼如下://接收客戶端發(fā)來的信息charszTemp[200];intn=m_ServerSocket->Receive(szTemp,200); //接收信息szTemp[n]='\0';CStringsTemp;sTemp.Format("收到:%s",szTemp);m_ListWords.AddString(sTemp); //顯示信息m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket類程序的指針實現(xiàn)“退出”按鈕的事件過程代碼如下:voidCChatServerDlg::OnBnClickedCancel(){ //TODO:在此添加控件通知處理程序代碼
SocketReset(); OnCancel();}2.2.3CAsyncSocket類程序的指針實現(xiàn)〔4〕運行比照。來運行一下這個程序,同時運行一下節(jié)的傳統(tǒng)機(jī)制程序,并將它們放在一個桌面上比照方圖2.45所示。2.2.3CAsyncSocket類程序的指針實現(xiàn)3.對話框指針機(jī)制的好處使用對話框指針機(jī)制的程序比傳統(tǒng)程序更有顯著的優(yōu)越性,主要表達(dá)在以下三個方面:〔1〕更加靈活?!?〕代碼更集中、更有條理?!?〕程序語句更加簡潔。2.2.4CSocket類編程1.創(chuàng)立工程、添加類、用戶界面分別創(chuàng)立客戶端和效勞器端工程,設(shè)置和前兩節(jié)的程序完全一樣,創(chuàng)立完成后分別在客戶和效勞器端工程中各添加一個基于CSocket類的MySocket類〔如圖2.46所示〕。2.2.4CSocket類編程再對照前兩節(jié)實例程序的界面給這個程序設(shè)計一個一模一樣的界面,如圖2.47所示。2.2.4CSocket類編程2.程序雛形架構(gòu)
客戶端。在MySocket.h中添加如下代碼:#include"Afxsock.h" //引用Afxsock.h頭文件,目的是使用CSocket類classCChatClientDlg; //為了能在MySocket類中定義主對話框類指針,先對主對話框類進(jìn)行
//前導(dǎo)聲明CChatClientDlg*m_dlg; //定義主對話框指針voidGetDlg(CChatClientDlg*dlg); //獲取主對話框指針的函數(shù)在ChatClientDlg.h中添加如下代碼:#include"MySocket.h"http://引用MySocket類的頭文件,是為了下面定義一個
//MySocket類對象指針MySocket*m_ClientSocket; //客戶端套接字指針CArchive*m_archiveIn; //收到的信息的存儲文件CArchive*m_archiveOut; //發(fā)送的信息的存儲文件CSocketFile*m_socketfile; //用于發(fā)送和接收數(shù)據(jù)的緩沖區(qū)voidOnReceive();voidOnClose();voidSocketReset();2.2.4CSocket類編程定義變量m_Input〔如圖2.48所示〕,用于后面接收對方發(fā)來的數(shù)據(jù):CStringm_Input;在ChatClientDlg.cpp中添加初始化代碼:m_ClientSocket=NULL;m_archiveIn=NULL;m_archiveOut=NULL;m_socketfile=NULL;2.2.4CSocket類編程在ChatClientDlg.cpp中寫出我們上面聲明的函數(shù)OnClose和OnReceive的函數(shù)體,為它們的實現(xiàn)代碼預(yù)留出空間,同時實現(xiàn)SocketReset()函數(shù),其代碼。在MySocket.cpp中實現(xiàn)獲取主對話框指針的GetDlg()函數(shù),并通過指針引用主對話框程序代碼中的網(wǎng)絡(luò)事件處理函數(shù):#include"ChatClientDlg.h"voidMySocket::GetDlg(CChatClientDlg*dlg)//獲得窗口界面的指針{ m_dlg=dlg;}voidMySocket::OnClose(intnErrorCode){ //TODO:在此添加專用代碼和/或調(diào)用基類
m_dlg->OnClose(); CSocket::OnClose(nErrorCode);}voidMySocket::OnReceive(intnErrorCode){ //TODO:在此添加專用代碼和/或調(diào)用基類
m_dlg->OnReceive(); AsyncSelect(FD_CLOSE|FD_READ|FD_WRITE); CSocket::OnReceive(nErrorCode);}2.2.4CSocket類編程效勞端。采用與客戶端類似的方法,在MySocket.h中添加如下代碼:#include"Afxsock.h"classCChatServerDlg;CChatServerDlg*m_dlg;voidGetDlg(CChatServerDlg*dlg);在ChatServerDlg.h中添加如下代碼:#include"MySocket.h"MySocket*m_ServerSocket; //MySocket類對象指針,用于動態(tài)生成與客戶通信的SocketMySocket*m_ListenSocket; //定義MySocket類對象指針,用于動態(tài)生成監(jiān)聽SocketCArchive*m_archiveIn;CArchive*m_archiveOut;CSocketFile*m_socketfile;voidOnReceive();voidOnClose();voidOnAccept();voidSocketReset();2.2.4CSocket類編程在ChatServerDlg.cpp中添加如下初始化代碼:m_ServerSocket=NULL;m_ListenSocket=NULL;m_archiveIn=NULL;m_archiveOut=NULL;m_socketfile=NULL;在ChatServerDlg.cpp中寫出OnAccept()、OnClose()、OnReceive()三個函數(shù)的函數(shù)體,為它們的實現(xiàn)代碼預(yù)留出空間,同時實現(xiàn)SocketReset函數(shù),其代碼。在MySocket.cpp中實現(xiàn)獲取主對話框指針的GetDlg()函數(shù),并通過指針引用主對話框的三個函數(shù),其代碼。2.2.4CSocket類編程3.代碼解析客戶端?!斑B接”按鈕的事件過程代碼?!皵嚅_”按鈕事件過程代碼如下:SocketReset();m_ListWords.AddString("從效勞器斷開");“發(fā)送”按鈕事件過程代碼如下:UpdateData();*m_archiveOut<<m_sWords;m_archiveOut->Flush();m_ListWords.AddString("發(fā)送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket類編程OnClose()函數(shù)代碼如下:m_ListWords.AddString("效勞器端斷開了");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);SocketReset();OnReceive()函數(shù)代碼如下:*m_archiveIn>>m_Input;m_archiveIn->Flush();m_ListWords.AddString("收到:"+m_Input);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket類編程“斷開”按鈕事件過程代碼如下:SocketReset();m_ListWords.AddString("從效勞器斷開");“發(fā)送”按鈕事件過程代碼如下:UpdateData();*m_archiveOut<<m_sWords;m_archiveOut->Flush();m_ListWords.AddString("發(fā)送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket類編程OnClose()函數(shù)代碼如下:m_ListWords.AddString("效勞器端斷開了");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);SocketReset();OnReceive()函數(shù)代碼如下:*m_archiveIn>>m_Input;m_archiveIn->Flush();m_ListWords.AddString("收到:"+m_Input);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket類編程效勞端?!伴_始監(jiān)聽”按鈕事件過程如下:if(!AfxSocketInit()) //初始化套接字{ MessageBox("WindowSocketinitialfailed!","Send",MB_ICONSTOP); return;}m_ListenSocket=newMySocket;m_ListenSocket->GetDlg(this);BYTEnFild[4];CStringsIP,sP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);sP.Format("%d",sPort);m_ListenSocket->Create(sPort,1,sIP); //創(chuàng)立效勞端監(jiān)聽Socketm_ListenSocket->Listen(1); //開始監(jiān)聽m_ListWords.AddString("監(jiān)聽開始:");m_ListWords.AddString("地址"+sIP+"端口"+sP);m_ListWords.Ad
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 法律實務(wù)合同審查技能知識要點梳理
- 《小學(xué)體育田徑運動基本技能訓(xùn)練教案》
- 安全管理文檔之班組長安全培訓(xùn)實施方案
- 2025年國網(wǎng)山東省電力公司招聘高校畢業(yè)生1300人(第一批)筆試參考題庫附帶答案詳解
- 2025年國家電網(wǎng)有限公司客戶服務(wù)中心招聘15人(第一批)筆試參考題庫附帶答案詳解
- 2025年上半年宜春市公安局交通警察支隊招考臨聘人員易考易錯模擬試題(共500題)試卷后附參考答案
- 2025年上半年宜昌市興山縣事業(yè)單位招考考試(66人)易考易錯模擬試題(共500題)試卷后附參考答案
- 2025年上半年定西市通渭縣事業(yè)單位及招考易考易錯模擬試題(共500題)試卷后附參考答案
- 2024福建泉州晉江市市政工程建設(shè)有限公司權(quán)屬公司招聘4人筆試參考題庫附帶答案詳解
- 2025年上半年安陽市湯陰縣事業(yè)單位招考易考易錯模擬試題(共500題)試卷后附參考答案
- 《珍愛生命拒絕毒品》主題班會課件
- GB/T 32399-2024信息技術(shù)云計算參考架構(gòu)
- 蘇教版二年級數(shù)學(xué)下冊單元測試題及答案全套1
- 河北張家口中國化工集團(tuán)盛華化工公司“11.28”重大爆燃事故調(diào)查報告
- 《知識產(chǎn)權(quán)法教程(第八版) 》 課件 王遷 第1-9章 總論、著作權(quán)法律制度概述-專利法律制度概述
- 07SG111-1 建筑結(jié)構(gòu)加固施工圖設(shè)計表示方法
- 屋頂分布式光伏發(fā)電EPC項目 投標(biāo)方案(技術(shù)方案)
- 網(wǎng)約車停運損失費起訴狀模板
- 中國急性缺血性卒中診治指南(2023)解讀
- A型肉毒素治療知情同意書 注射知情同意書
- 血液透析導(dǎo)管溶栓及護(hù)理
評論
0/150
提交評論