使用MFC類庫(kù)實(shí)現(xiàn)回聲程序

Zhangtaolmq  2010/04/16

 

程序名稱:回聲程序

程序功能:客戶端把數(shù)據(jù)發(fā)送給服務(wù)端,服務(wù)端收到數(shù)據(jù)后,立即將數(shù)據(jù)原樣返回給客戶端。

 

一. 客戶端的創(chuàng)建

 

1 使用[MFC AppWizard (exe)]創(chuàng)建一個(gè)[Dialog Based]項(xiàng)目:CSockClient

2 設(shè)計(jì)對(duì)話框

 去掉OkCancle兩個(gè)按鈕,增加ID_Connect(連接)、ID_Send(發(fā)送)、ID_Exit(關(guān)閉)按鈕,增加ListBox控件IDC_LISTMSGEdit控件IDC_EDITMSG,并按下表在ClassWizard中為CCSockClientDlg類添加變量。

 

 

3 CAsyncSocket類用DoCallBack函數(shù)處理MFC消息,當(dāng)一個(gè)網(wǎng)絡(luò)事件發(fā)生時(shí),DoCallBack函數(shù)按網(wǎng)絡(luò)事件類型:FD_READFD_WRITEFD_ACCEPTFD_CONNECT分別調(diào)用OnReceiveOnSendOnAcceptOnConnect函數(shù)。由于MFC把這些事件處理函數(shù)定義為虛函數(shù),所以要生成一個(gè)新的C++類,以重載這些函數(shù)

網(wǎng)絡(luò)事件

FD_READ

FD_WRITE

FD_ACCEPT

FD_CONNECT

回調(diào)函數(shù)

OnReceive

OnSend

OnAccept

OnConnect

 

做法如下:

l  Public方式繼承CAsyncSocket類,生成新類MySock

l  MySock類添加虛函數(shù)OnReceiveOnConnectOnSend

 

4 [MySock.ccp]中添加以下代碼

#include "CSockClient.h"

#include "CSockClientDlg.h"

 

5 [MySock.h]中添加以下代碼

public:

      BOOL m_bConnected;    //是否連接

      UINT m_nLength;        //消息長(zhǎng)度

      char m_szBuffer[4096];    //消息緩沖區(qū)

 

6 [MySock.ccp]中重載各函數(shù)

 

MySock::MySock()

{

m_nLength=0;

memset(m_szBuffer,0,sizeof(m_szBuffer));

m_bConnected=FALSE;

}

 

MySock::~MySock()

{

//關(guān)閉套接字

if(m_hSocket!=INVALID_SOCKET)

      Close();

}

 

void MySock::OnReceive(int nErrorCode)

{

m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);

//下面兩行代碼用來(lái)獲取對(duì)話框指針

CCSockClientApp* pApp=(CCSockClientApp*)AfxGetApp();

CCSockClientDlg* pDlg=(CCSockClientDlg*)pApp- >m_pMainWnd;

pDlg- >m_MSGS.InsertString(0,m_szBuffer);

memset(m_szBuffer,0,sizeof(m_szBuffer));

CAsyncSocket::OnReceive(nErrorCode);

}

 

void MySock::OnSend(int nErrorCode)

{

Send(m_szBuffer,m_nLength,0);

m_nLength=0;

memset(m_szBuffer,0,sizeof(m_szBuffer));

//繼續(xù)提請(qǐng)一個(gè)“讀”的網(wǎng)絡(luò)事件,接收Server消息

AsyncSelect(FD_READ);

CAsyncSocket::OnSend(nErrorCode);

}

 

void MySock::OnConnect(int nErrorCode)

{

if (nErrorCode==0)

{

      m_bConnected=TRUE;

      CCSockClientApp* pApp=(CCSockClientApp*)AfxGetApp();

      CCSockClientDlg* pDlg=(CCSockClientDlg*)pApp- >m_pMainWnd;

      memcpy(m_szBuffer,"Connected to ",13);

      strncat(m_szBuffer,pDlg- >m_szServerAdr,

          sizeof(pDlg- >m_szServerAdr));

      pDlg- >m_MSGS.InsertString(0,m_szBuffer);

      ///提請(qǐng)一個(gè)“讀”的網(wǎng)絡(luò)事件,準(zhǔn)備接收

AsyncSelect(FD_READ);    /

}

CAsyncSocket::OnConnect(nErrorCode);

}

 

7 新建對(duì)話框IDD_Addr,用來(lái)輸入IP地址和Port;生成新類CAddrDlg。增加兩個(gè)Edit控件:IDC_AddrIDC_Port按下表在ClassWizard中為CAddrDlg類添加變量。

8 [CSockClientDlg.ccp]中添加代碼

 

#include "AddrDlg.h"

protected:

int TryCount;

MySock m_clientSocket;

UINT m_szPort;

public:

char m_szServerAdr[256];

 

9 雙擊[IDD_CSOCKCLIENT_DIALOG]對(duì)話框中的“連接”按鈕,添加以下代碼

 

void CCSockClientDlg::OnConnect()

{

m_clientSocket.ShutDown(2);

m_clientSocket.m_hSocket=INVALID_SOCKET;

m_clientSocket.m_bConnected=FALSE;

CAddrDlg m_Dlg;

//默認(rèn)端口1088

m_Dlg.m_Port=1088;

if (m_Dlg.DoModal()==IDOK && !m_Dlg.m_Addr.IsEmpty())

{

      memcpy(m_szServerAdr,m_Dlg.m_Addr,sizeof(m_szServerAdr));

      m_szPort=m_Dlg.m_Port;

      //建立計(jì)時(shí)器,每1秒嘗試連接一次,直到連上或TryCount>10

SetTimer(1,1000,NULL);

      TryCount=0;

}

}

 

 10 添加Windows消息WM_TIMER響應(yīng)函數(shù)OnTimer

 

void CCSockClientDlg::OnTimer(UINT nIDEvent)

{

if (m_clientSocket.m_hSocket==INVALID_SOCKET)

{

      BOOL bFlag=m_clientSocket.Create(0,SOCK_STREAM,FD_CONNECT);

      if(!bFlag)

      {

       AfxMessageBox("Socket Error!");

       m_clientSocket.Close();

       PostQuitMessage(0);

       return;

      }

}

m_clientSocket.Connect(m_szServerAdr,m_szPort);

TryCount++;

if (TryCount >=10 || m_clientSocket.m_bConnected)

{

      KillTimer(1);

      if (TryCount >=10)

       AfxMessageBox("Connect Failed!");

      return;

}

CDialog::OnTimer(nIDEvent);

}

 

 11 雙擊IDD_CSOCKCLIENT_DIALOG對(duì)話框中的“發(fā)送”按鈕,添加以下代碼

 

void CCSockClientDlg::OnSend()

{

if (m_clientSocket.m_bConnected)

{

m_clientSocket.m_nLength=m_MSG.GetWindowText

(m_clientSocket.m_szBuffer, sizeof(m_clientSocket.m_szBuffer));

      m_clientSocket.AsyncSelect(FD_WRITE);

      m_MSG.SetWindowText("");

}

}

 

12 雙擊[IDD_CSOCKCLIENT_DIALOG]對(duì)話框中的“[關(guān)閉]”按鈕,添加以下代碼

 

void CCSockClientDlg::OnExit()

{

//關(guān)閉Socket

m_clientSocket.ShutDown(2);

//關(guān)閉對(duì)話框

EndDialog(0);

}

 

13.運(yùn)行此項(xiàng)目,連接時(shí)輸入主機(jī)名或IP均可,CAsyncSocket類會(huì)自動(dòng)處理。

 

 

二. 服務(wù)端的創(chuàng)建

 

Server端的編程與Client端的類似,下面主要介紹他的ListenAccept函數(shù)

1 建立一個(gè)CNewSocket類,重載CAsyncSocket類的OnReceiveOnSend函數(shù),如何進(jìn)行信息的顯示和發(fā)送可以參考Client程序。本例中采用將收到信息原封不動(dòng)發(fā)回的方法來(lái)實(shí)現(xiàn)Echo功能,代碼如下

CNewSocket::OnReceiveint nErrorCOde

{

m_nLength=Receivem_szBuffersizeofm_szBuffer),0);

// 直接轉(zhuǎn)發(fā)消息

AsyncSelectFD_WRITE);

}

 

CNewSocket::OnSendint nErrorCode

{

Sendm_szBufferm_nLength0);

}

 

2 建立一個(gè)CMyServerSocket類,重載CAsyncSocket類的OnAccept函數(shù)代碼如下

MyServerSocket.h中聲明變量

public:

CNewSocket*    m_pSocket

 

void CMyServerSocket::OnAcceptint nErrorCode

{

//偵聽(tīng)到連接請(qǐng)求,調(diào)用Accept函數(shù)

CNewSocket* pSocket = new CNewSocket();

if Accept*pSocket))

{

      pSocket- >AsyncSelectFD_READ

m_pSocket=pSocket

}

else

      delete pSocket

}

3 為對(duì)話框添加一個(gè)“偵聽(tīng)”按鈕,添加如下代碼

CsockServerDlg.ccp中聲明變量

public

CMyServerSocket    m_srvrSocket;

void CCSockServerDlg::OnListen()

{

if m_srvrSocket.m_hSocket==INVALID_SOCKET

{

      BOOL bFlag=m_srvrSocket.Create(UserPorSOCK_STREAMFD_ACCEPT)

      if (!bFlag

      {

       AfxMessageBox(“Socket Error!”);

       M_srvrSocket.Close();

       PostQuitMessage0);

       Return

      }

}

//“偵聽(tīng)”成功,等待連接請(qǐng)求

if (!m_srvrSocket.Listen1))

{

      int nErrorCode = m_srvrSocket.GetLastError();

      if nError=WSAEWOULDBLOCK

      {

       AfxMessageBox(“Socket Error!”);

       M_srvrSocket.Close();

       PostQuitMessage0);

       Return

      }

}

}

 測(cè)試

 

注意:

1. InitInstance()中加上

if (!AfxSocketInit())

       {

              AfxMessageBox("AfxSocketInit() failed");

              return FALSE;

       }

2. [stdafx.h]中添加#include <afxsock.h>      

 

     zhangtaolmq