近年來(lái),利用Internet進(jìn)行網(wǎng)際間通訊,在WWW瀏 覽、FTP、Gopher這些常規(guī)服務(wù),以及在網(wǎng)絡(luò)電話、多媒體會(huì)議等這些對(duì)實(shí)時(shí)性要求嚴(yán)格 的應(yīng)用中成為研究的熱點(diǎn),而且已經(jīng)是必需的了。Windows環(huán)境下進(jìn)行通訊程序設(shè)計(jì)的最基本方法是應(yīng)用Windows Sockets實(shí)現(xiàn)進(jìn)程間的通訊,為此微軟提供了大量基于Windows Sockets的通訊API,如WinSockAPI、WinInetAPI和ISAPI,并一直致力于開(kāi)發(fā)更快、 更容易的通訊API,將其和MFC集成在一起以使通訊編程越來(lái)越容易。本實(shí)例重點(diǎn)介紹使用MFC的CSocket類(lèi)編寫(xiě)網(wǎng)絡(luò)通訊程序的方法,并通過(guò)使用CSocket類(lèi)實(shí)現(xiàn)了網(wǎng)絡(luò)聊天程序。程序編譯運(yùn)行后的界面效果如圖一所示:
一、實(shí)現(xiàn)方法
微軟的MFC把復(fù)雜的WinSock API函數(shù)封裝到類(lèi)里,這使得編寫(xiě)網(wǎng)絡(luò)應(yīng)用程序更容易。CAsyncSocket類(lèi)逐個(gè)封裝了WinSock API,為高級(jí)網(wǎng)絡(luò)程序員 提供了更加有力而靈活的方法。這個(gè)類(lèi)基于程序員了解網(wǎng)絡(luò)通訊的假設(shè),目的是為了在MFC中使用WinSock,程序員有責(zé)任處理諸如阻塞、字節(jié)順序和在Unicode與MBCS 間轉(zhuǎn)換字符的任務(wù)。為了給程序員提供更方便的接口以自動(dòng)處理這些任務(wù),MFC給出 了CSocket類(lèi),這個(gè)類(lèi)是由CAsyncSocket類(lèi)繼承下來(lái)的,它提供了比CAsyncSocket更高層的WinSock API接口。Csocket類(lèi)和CsocketFile類(lèi)可以與Carchive類(lèi)一起合作來(lái)管理發(fā)送和接收的數(shù)據(jù),這使管理數(shù)據(jù)收發(fā)更加便利。CSocket對(duì)象提供阻塞模式,這對(duì)于Carchive的同步操作是至關(guān)重要的。阻塞函數(shù)(如Receive()、Send()、ReceiveFrom()、SendTo() 和Accept())直到操作完成后才返回控制權(quán),因此如果需要低層控制和高效率,就使用CasyncSock類(lèi);如果需要方便,則可使用Csocket類(lèi)。
一些網(wǎng)絡(luò)應(yīng)用程序(如網(wǎng)絡(luò)電話、多媒體會(huì)議工具)對(duì)實(shí)時(shí)性要求非常強(qiáng),要求能夠直接應(yīng)用WinSock發(fā)送和接收數(shù)據(jù)。為了充分利用MFC 的優(yōu)勢(shì),首選方案應(yīng)當(dāng)是MFC中的CAsyncSocket類(lèi)或CSocket類(lèi),這兩個(gè)類(lèi)完全封裝了WinSock API,并提供更多的便利。本實(shí)例介紹應(yīng)用這兩個(gè)類(lèi)的編程模型,并引出相關(guān)的成員函數(shù)與一些概念的解釋。
CSocket類(lèi)是由CAsyncSocket繼承而來(lái)的,事實(shí)上,在MFC中CAsyncSocket 逐個(gè)封裝了WinSock API,每個(gè)CAsyncSocket對(duì)象代表一個(gè)Windows Socket對(duì)象,使用CAsyncSocket 類(lèi)要求程序員對(duì)網(wǎng)絡(luò)編程較為熟悉。相比起來(lái),CSocket類(lèi)是CAsyncSocket的派生類(lèi), 繼承了它封裝的WinSock API。
一個(gè)CSocket對(duì)象代表了一個(gè)比CAsyncSocket對(duì)象更高層次的Windows Socket的抽象,CSocket類(lèi)與CSocketFile類(lèi)和CArchive類(lèi)一起工作來(lái)發(fā)送和接收數(shù)據(jù),因此使用它更加容易使用。CSocket對(duì)象提供阻塞模式,因?yàn)樽枞?能對(duì)于CArchive的同步操作是至關(guān)重要的。在這里有必要對(duì)阻塞的概念作一解釋?zhuān)?一個(gè)socket可以處于"阻塞模式"或"非阻塞模式",當(dāng)一個(gè)套接字處于阻塞模式(即同步操作)時(shí),它的阻塞函數(shù)直到操作完成才會(huì)返回控制權(quán),之所以稱(chēng)為阻塞是因?yàn)榇颂捉幼值淖枞瘮?shù)在完成操作返回之前什么也不能做。如果一個(gè)socket處于非阻塞模式(即異步操作),則會(huì)被調(diào)用函數(shù)立即返回。在CAsyncSocket類(lèi)中可以用GetLastError 成員函數(shù)查詢最后的錯(cuò)誤,如果錯(cuò)誤是WSAEWOULDBLOCK則說(shuō)明有阻塞,而CSocket絕不會(huì)返回WSAEWOULDBLOCK,因?yàn)樗约汗芾碜枞N④浗ㄗh盡量使用非阻塞模式,通過(guò)網(wǎng)絡(luò)事件的發(fā)生而通知應(yīng)用程序進(jìn)行相應(yīng)的處理。但在CSocket類(lèi)中,為了利用CArchive 處理通訊中的許多問(wèn)題和簡(jiǎn)化編程,它的一些成員函數(shù)總是具有阻塞性質(zhì)的,這是因?yàn)镃Archive類(lèi)需要同步的操作。
在Win32環(huán)境下,如果要使用具有阻塞性質(zhì)的套接字,應(yīng)該放在獨(dú)立的工作線程中處理,利用多線程的方法使阻塞不至于干擾其他線程,也不會(huì)把CPU時(shí)間浪費(fèi)在阻塞上。多線程的方法既可以使程序員享受CSocket帶 來(lái)的簡(jiǎn)化編程的便利,也不會(huì)影響用戶界面對(duì)用戶的反應(yīng)。
CAsyncSocket類(lèi)編程模型
在一個(gè)MFC應(yīng)用程序中,要想輕松處理多個(gè)網(wǎng) 絡(luò)協(xié)議,而又不犧牲靈活性時(shí),可以考慮使用CAsyncSocket類(lèi),它的效率比CSocket 類(lèi)要高。CAsyncSocket類(lèi)針對(duì)字節(jié)流型套接字的編程模型簡(jiǎn)述如下:
1、構(gòu)造一個(gè)CAsyncSocket對(duì)象,并用這個(gè) 對(duì)象的Create成員函數(shù)產(chǎn)生一個(gè)Socket句柄。可以按如下兩種方法構(gòu)造:
CAsyncSocket sock; //使用默認(rèn)參數(shù)產(chǎn)生一個(gè)字節(jié)流套接字 Sock.Create();
|
或在指定端口號(hào)產(chǎn)生一個(gè)數(shù)據(jù)報(bào)套接字
CAsyncSocket*pSocket=newCAsyncSocket; intnPort=27; pSocket->Create(nPort,SOCK-DGRAM);
|
第一種方法在棧上產(chǎn)生一個(gè)CAsyncSocket對(duì)象, 而第二種方法在堆上產(chǎn)生CAsyncSocket對(duì)象;第一種方法中Create()成員函數(shù)用缺省參數(shù)產(chǎn)生一個(gè)字節(jié)流套接字,第二種方法中用Create()成員函數(shù)在指定的端口產(chǎn)生一個(gè)數(shù)字報(bào)套接字。Create()函數(shù)的原型為:
BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, LPCTSTR lpszSocketAddress = NULL );
|
該函數(shù)的參數(shù)有:
1)端口,UINT類(lèi)型。注意:如果是服務(wù)方,則使 用一個(gè)眾所周知的端口供服務(wù)方連接;如果是客戶方,典型做法是接受默認(rèn)參數(shù),使 套接字可以自主選擇一個(gè)可用端口;
2)socket 類(lèi)型,可以是SOCK-STREAM(默認(rèn)值,字節(jié)流)或SOCK-DGRAM(數(shù)據(jù)報(bào));
3)socket的地址,例如"
ftp.gliet.edu.cn
"或"202.193.64.33"。
2、如是客戶方程序,用CAsyncSocket∷Connect()成員函數(shù)連接到服務(wù)方;如是服務(wù)方程序,用CAsyncSocket∷Listen()成員函數(shù)開(kāi)始 監(jiān)聽(tīng),一旦收到連接請(qǐng)求,則調(diào)用CAsyncSocket∷Accept()成員函數(shù)開(kāi)始接收。注意:CAsyncSocket ∷Accept()成員函數(shù)要用一個(gè)新的并且是空的CAsyncSocket對(duì)象作為它的參數(shù),這里所說(shuō) 的"空的"指的是這個(gè)新對(duì)象還沒(méi)有調(diào)用Create()成員函數(shù)。
3、調(diào)用其他的CAsyncSocket類(lèi)的Receive()、ReceiveFrom()、Send()和SendTo()等成員函數(shù)進(jìn)行數(shù)據(jù)通信。
4、通訊結(jié)束后,銷(xiāo)毀CAsyncSocket對(duì)象。如果是在棧上產(chǎn)生的CAsyncSocket對(duì)象,則對(duì)象超出定義的范圍時(shí)自動(dòng)被析構(gòu);如果是在堆上產(chǎn)生,也就是用了new這個(gè)操作符,則必須使用delete操作符銷(xiāo)毀CAsyncSocket 對(duì)象。
CSocket類(lèi)編程模型
使用CSocket對(duì)象涉及CArchive和CSocketFile 類(lèi)對(duì)象。以下介紹的針對(duì)字節(jié)流型套接字的操作步驟中,只有第3步對(duì)于客戶方和服務(wù)方操作是不同的,其他步驟都相同。
1、構(gòu)造一個(gè)CSocket對(duì)象。
2、使用這個(gè)對(duì)象的Create()成員函數(shù)產(chǎn)生一個(gè)socket對(duì)象。在客戶方程序中,除非需要數(shù)據(jù)報(bào)套接字,Create()函數(shù)一般情況下應(yīng)該使用默認(rèn)參數(shù)。而對(duì)于服務(wù)方程序,必須在調(diào)用Create時(shí)指定一個(gè)端口。需要注意的是,Carchive類(lèi)對(duì)象不能與數(shù)據(jù)報(bào)(UDP)套接字一起工作,因此對(duì)于數(shù)據(jù)報(bào)套接字,CAsyncSocket和CSocket 的使用方法是一樣的。
3、如果是客戶方套接字,則調(diào)用CAsyncSocket ∷Connect()函數(shù)與服務(wù)方套接字連接;如果是服務(wù)方套接字,則調(diào)用CAsyncSocket∷Listen()開(kāi)始監(jiān)聽(tīng)來(lái)自客戶方的連接請(qǐng)求,收到連接請(qǐng)求后,調(diào)用CAsyncSocket∷Accept()函數(shù)接受請(qǐng)求,建立連接。請(qǐng)注意Accept()成員函數(shù)需要一個(gè)新的并且為空的CSocket對(duì)象作為它的參數(shù),解釋同上。
4、產(chǎn)生一個(gè)CSocketFile對(duì)象,并把它與CSocket 對(duì)象關(guān)聯(lián)起來(lái)。
5、為接收和發(fā)送數(shù)據(jù)各產(chǎn)生一個(gè)CArchive 對(duì)象,把它們與CSocketFile對(duì)象關(guān)聯(lián)起來(lái)。切記CArchive是不能和數(shù)據(jù)報(bào)套接字一起工作的。
6、使用CArchive對(duì)象的Read()、Write()等函數(shù)在客戶與服務(wù)方傳送數(shù)據(jù)。
7、通訊完畢后,銷(xiāo)毀CArchive、CSocketFile和CSocket對(duì)象。
二、編程步驟
1、 啟動(dòng)Visual C++6.0,生成一個(gè)基于對(duì)話框架的應(yīng)用程序,將該程序命名為"Test";
2、 按照?qǐng)D一所示的效果圖設(shè)置對(duì)話框的界面;
3、 使用Class Wizard為應(yīng)用程序的按鈕添加鼠標(biāo)單擊消息響應(yīng)函數(shù);
4、 使用Class Wizard在應(yīng)用程序中定義新類(lèi)CNewSocket,其基類(lèi)選擇為CSocket;
5、 添加代碼,編譯運(yùn)行程序。
三、程序代碼
////////////////////////////////////////////////// NewSocket.h : header file #if !defined(AFX_NEWSOCKET_H__8CE2ED73_1D56_11D3_9928_00A0C98F3E85__INCLUDED_) #define AFX_NEWSOCKET_H__8CE2ED73_1D56_11D3_9928_00A0C98F3E85__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 class CTestDlg; #include <afxsock.h>
class CNewSocket : public CSocket { // Attributes public:
// Operations public: CNewSocket(); virtual ~CNewSocket();
// Overrides public: int m_Status; void GetDlg(CTestDlg *dlg); CTestDlg *m_dlg; // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CNewSocket) public: virtual void OnAccept(int nErrorCode); virtual void OnReceive(int nErrorCode); virtual void OnClose(int nErrorCode); //}}AFX_VIRTUAL // Generated message map functions //{{AFX_MSG(CNewSocket) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG // Implementation protected: }; #endif
//////////////////////////////////////////////////////// NewSocket.cpp : implementation file #include "stdafx.h" #include "Test.h" #include "NewSocket.h" #include "TestDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
CNewSocket::CNewSocket() {}
CNewSocket::~CNewSocket() {}
#if 0 BEGIN_MESSAGE_MAP(CNewSocket, CSocket) //{{AFX_MSG_MAP(CNewSocket) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0
void CNewSocket::OnAccept(int nErrorCode) { if (m_dlg->m_ClientSocket==NULL) m_dlg->OnAccept(); CSocket::OnAccept(nErrorCode); }
void CNewSocket::OnReceive(int nErrorCode) { m_dlg->OnReceive(); CSocket::OnReceive(nErrorCode); }
void CNewSocket::GetDlg(CTestDlg *dlg) { m_dlg=dlg; }
void CNewSocket::OnClose(int nErrorCode) { m_dlg->OnClose(); CSocket::OnClose(nErrorCode); }
///////////////////////////////////////////////////////////////// TestDlg.h : header file #if !defined(AFX_TESTDLG_H__EDDDE196_1BF1_11D3_BE77_0000B454AEE4__INCLUDED_) #define AFX_TESTDLG_H__EDDDE196_1BF1_11D3_BE77_0000B454AEE4__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 #include "NewSocket.h"
class CTestDlg : public CDialog { // Construction public: void SocketReset(); void OnClose(); void OnReceive(); void OnAccept(); CSocketFile *m_file; CArchive *m_arOut; CArchive *m_arIn; CNewSocket* m_ServerSocket; CNewSocket* m_ClientSocket; CTestDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CTestDlg) enum { IDD = IDD_TEST_DIALOG }; CString m_Info; CString m_Output; CString m_Input; CString m_Connect; CString m_IPAddress; UINT m_Port; int m_Status; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CTestDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: HICON m_hIcon; // Generated message map functions //{{AFX_MSG(CTestDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnConnect(); afx_msg void OnDisconnect(); afx_msg void OnSend(); afx_msg void OnServerradio(); afx_msg void OnClientradio(); afx_msg void OnSendclear(); afx_msg void OnReceiveclear(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #endif
//////////////////////////////////////////////////////////////// TestDlg.cpp : implementation file #include "stdafx.h" #include "Test.h" #include "TestDlg.h" #include <afxsock.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() };
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT }
void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP }
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP()
CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/) : CDialog(CTestDlg::IDD, pParent) { //{{AFX_DATA_INIT(CTestDlg) m_Info = _T(""); m_Output = _T(""); m_Input = _T(""); m_Connect = _T(""); m_IPAddress = _T(""); m_Port = 0; m_Status = -1; //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }
void CTestDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CTestDlg) DDX_Text(pDX, IDC_OUTPUTEDIT, m_Output); DDX_Text(pDX, IDC_INPUTEDIT, m_Input); DDX_Text(pDX, IDC_CONNECTEDIT, m_Connect); DDX_Text(pDX, IDC_IPADDRESS, m_IPAddress); DDV_MaxChars(pDX, m_IPAddress, 15); DDX_Text(pDX, IDC_PORT, m_Port); DDX_Radio(pDX, IDC_SERVERRADIO, m_Status); //}}AFX_DATA_MAP }
BEGIN_MESSAGE_MAP(CTestDlg, CDialog) //{{AFX_MSG_MAP(CTestDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_CONNECTBUTTON, OnConnect) ON_BN_CLICKED(IDC_DISCONNECTBUTTON, OnDisconnect) ON_BN_CLICKED(IDC_SENDBUTTON, OnSend) ON_BN_CLICKED(IDC_SERVERRADIO, OnServerradio) ON_BN_CLICKED(IDC_CLIENTRADIO, OnClientradio) ON_BN_CLICKED(IDC_SENDCLEARBUTTON, OnSendclear) ON_BN_CLICKED(IDC_RECEIVECLEARBUTTON, OnReceiveclear) //}}AFX_MSG_MAP END_MESSAGE_MAP()
BOOL CTestDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon m_Status=-1; m_ServerSocket=NULL; m_ClientSocket=NULL; m_arIn=NULL; m_arOut=NULL; m_file=NULL; m_Connect=""; m_IPAddress="202.207.243.29"; m_Port=5000; GetDlgItem(IDC_IPADDRESS)->EnableWindow(FALSE); GetDlgItem(IDC_PORT)->EnableWindow(FALSE); UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control }
void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } }
// If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CTestDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } }
// The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CTestDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; }
void CTestDlg::OnConnect() { CString msg; UpdateData(TRUE); if (m_Status==0 ) //server { if ( m_ServerSocket!=NULL) { m_Connect="Please disconnect!"; UpdateData(FALSE); } else { m_Connect="Waiting for Client..."; UpdateData(FALSE); if(!AfxSocketInit()) { MessageBox("WindowsSocket initial failed!","Send",MB_ICONSTOP); return; } m_ServerSocket=new CNewSocket; m_ServerSocket->m_Status=m_Status; m_ServerSocket->GetDlg(this); if(!m_ServerSocket->Create(m_Port)) MessageBox("SendSocket create failed!", "Send",MB_ICONSTOP); else { m_ServerSocket->Listen(); } } } else { if (m_Status==1) { if (m_ClientSocket!=NULL) { m_Connect="Please disconnect!"; UpdateData(FALSE); } else { m_Connect="Connect to the Server..."; UpdateData(FALSE); if(!AfxSocketInit()) { MessageBox("WindowsSocket initial failed!","Receive",MB_ICONSTOP); return; } m_ClientSocket=new CNewSocket; m_ClientSocket->GetDlg(this); m_ClientSocket->m_Status=m_Status; if(!m_ClientSocket->Create()) { MessageBox("ReceiveSocket create failed!","Receive",MB_ICONSTOP); return; } else { if (!m_ClientSocket->Connect(m_IPAddress,m_Port)) { CString str=m_Connect; SocketReset(); m_Connect=str; m_Connect+="Error!"; UpdateData(FALSE); } else { m_Connect+="OK!"; m_file=new CSocketFile(m_ClientSocket); m_arIn=new CArchive(m_file, CArchive::load); m_arOut=new CArchive(m_file, CArchive::store); } UpdateData(FALSE); } } } } if (m_Status==-1) { msg="Please choose the status!"; AfxMessageBox(msg); } }
void CTestDlg::OnSend() { if (m_arOut) { if (m_Status==0) { UpdateData(TRUE); *m_arOut<<m_Output; m_arOut->Flush(); } else { UpdateData(TRUE); *m_arOut<<m_Output; m_arOut->Flush(); } } else AfxMessageBox("Not connected!"); }
void CTestDlg::OnAccept() { m_Connect+="OK!"; UpdateData(FALSE); m_ClientSocket=new CNewSocket; m_ClientSocket->GetDlg(this); m_ServerSocket->Accept(*m_ClientSocket); m_ClientSocket->m_Status=m_ServerSocket->m_Status; m_file=new CSocketFile(m_ClientSocket); m_arIn=new CArchive(m_file, CArchive::load); m_arOut=new CArchive(m_file, CArchive::store); }
void CTestDlg::OnReceive() { *m_arIn>>m_Input; UpdateData(FALSE); }
void CTestDlg::OnDisconnect() { if (m_arOut!=NULL) { SocketReset(); m_Connect="Disconnected!"; UpdateData(FALSE); } }
void CTestDlg::OnClose() { if (m_ClientSocket->m_Status==0) m_Connect="Client "; else m_Connect="Server "; m_Connect+="has disconnected!"; UpdateData(FALSE); }
void CTestDlg::SocketReset() { if (m_arIn!=NULL) { delete m_arIn; m_arIn=NULL; } if (m_arOut!=NULL) { delete m_arOut; m_arOut=NULL; } if (m_file!=NULL) { delete m_file; m_file=NULL; } if (m_ClientSocket!=NULL) { delete m_ClientSocket; m_ClientSocket=NULL; } if (m_ServerSocket!=NULL) { delete m_ServerSocket; m_ServerSocket=NULL; } m_Connect=""; UpdateData(FALSE); }
void CTestDlg::OnServerradio() { UpdateData(TRUE); GetDlgItem(IDC_IPADDRESS)->EnableWindow(FALSE); GetDlgItem(IDC_PORT)->EnableWindow(TRUE); UpdateData(FALSE); }
void CTestDlg::OnClientradio() { UpdateData(TRUE); GetDlgItem(IDC_IPADDRESS)->EnableWindow(TRUE); GetDlgItem(IDC_PORT)->EnableWindow(TRUE); UpdateData(FALSE); }
void CTestDlg::OnSendclear() { m_Output=""; UpdateData(FALSE); }
void CTestDlg::OnReceiveclear() { m_Input=""; UpdateData(FALSE); }
|
四、小結(jié)
本實(shí)例介紹了CAsyncSocket、CSocket類(lèi),并通過(guò)使用CSocket類(lèi)實(shí)現(xiàn)了網(wǎng)絡(luò)聊天程序。讀者朋友還可以通過(guò)MFC CArchive 對(duì)象進(jìn)行信息的接發(fā)操作,使得網(wǎng)絡(luò)傳輸如同使用MFC的文檔連載協(xié)議(Serialization protocol),簡(jiǎn)捷易用。