首页 > 编程资源分享区 > C/C++源代码共享 > 用MFC快速网络编程
2006
04-17

用MFC快速网络编程

随着计算机网络化的深入,计算机网络编程在程序设计的过程中变得日益重要。由于C ++语言对底层操作的优越性,许多文章都曾经介绍过用VC ++进行Socket 编程的方法。但由于都是直接利用动态连接库wsock32.dll 进行操作,实现起来比较烦琐。其实,VC ++的MFC 类库中提供了CAsyncSocket 这样一个套接字类,用他来实现Socket 编程,是非常方便的。

  本文将用一个Echo 例程来介绍CAsyncSocket 类的用法。

  一、客户端

  1 .创建一个Dialog Based 项目
  CSockClient。
  2 .设计对话框

  去掉Ok 和Cancle 两个按钮,增加ID_Connect (连接)、ID_Send(发送)、ID_Exit(关闭)按钮,增加ListBox 控件IDC_LISTMSG 和Edit 控件IDC_EDITMSG,并按下表在ClassWizard 中为CCSockClientDlg 类添加变量。
vc72_1.jpg (11377 字节)
  3 .CAsyncSocket 类用DoCallBack 函数处理MFC 消息

  当一个网络事件发生时,DoCallBack 函数按网络事件类型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT 分别调用OnReceive、OnSend、OnAccept、OnConnect 函数。由于MFC 把这些事件处理函数定义为虚函数,所以要生成一个新的C ++类,以重载这些函数,做法如下:
  以Public 方式继承CAsyncSocket 类,生成新类MySock;
  为MySock 类添加虚函数OnReceive、OnConnect、OnSend

  4 .在MySock.ccp 中添加以下代码

  #include “CSockClient.h”
  #include “CSockClientDlg.h”
  5 .在MySock.h 中添加以下代码

  public:
   BOOL m_bConnected; // 是否连接
   UINT m_nLength;// 消息长度
   char m_szBuffer[4096];// 消息缓冲区
  6 .在MySock.ccp 中重载各函数

  MySock::MySock()
  {
   m_nLength=0;
   memset(m_szBuffer,0,sizeof(m_szBuffer));
   m_bConnected=FALSE;
  }

  MySock:: ~MySock()
  {
   // 关闭套接字
  if(m_hSocket!=INVALID_SOCKET)
     Close();
  }

  void MySock::OnReceive(int nErrorCode)
  {
  m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);
  // 下面两行代码用来获取对话框指针
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));
   // 继续提请一个” 读” 的网络事件,
   // 接收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);
   AsyncSelect(FD_READ);
   // 提请一个” 读” 的网络事件,准备接收
   }
   CAsyncSocket::OnConnect(nErrorCode);
}
  7 .新建对话框IDD_Addr

  用来输入IP 地址和Port;生成新类CAddrDlg。增加两个Edit 控件:IDC_Addr、IDC_Port 按下表在ClassWizard 中为CAddrDlg 类添加变量。
vc72_2.jpg (10346 字节)
  8 .在CSockClientDlg.ccp 中添加代码

  #include “AddrDlg.h”
  protected:
   int TryCount;
   MySock m_clientSocket;
   UINT m_szPort;
  public:
   char m_szServerAdr[256];   
  9 .双击IDD_CSOCKCLIENT_DIALOG 对话框中的” 连接” 按钮,添加以下代码

  void CCSockClientDlg::OnConnect()
  {
   m_clientSocket.ShutDown(2);
   m_clientSocket.m_hSocket=INVALID_SOCKET;
   m_clientSocket.m_bConnected=FALSE;
   CAddrDlg m_Dlg;
   // 默认端口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;
    // 建立计时器,每1 秒尝试连接一次,
    // 直到连上或TryCount>10
  SetTimer(1,1000,NULL);
    TryCount=0;
   }
}
  10 .添加Windows 消息WM_TIMER 响应函数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 对话框中的” 发送” 按钮,添加以下代码

  void CCSockClientDlg::OnSend()
  {
   if (m_clientSocket.m_bConnected)
   {
   m_clientSocket.m_nLength=m_MSG.GetWindow


留下一个回复