dazhong

导航

使用MFC快速实现网络编程

随着算机网化的深入,算机网络编程在程序设计程中得日益重要。

由于C++操作的越性,多文章都曾绍过VC++Socket

程的方法。但由于都是直接利用动态连wsock32.dll行操作,实现

VC++MFC类库中提供了CAsyncSocket这样一个套接字,用他来实现

Socket程,是非常方便的。

 

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

 

一.

 

1 建一个Dialog Based目:CSockClient

 

2 设计对话

 

去掉OkCancle两个按,增加ID_Connect接)、ID_Send送)、

ID_Exit关闭)按,增加ListBox控件IDC_LISTMSGEdit控件IDC_EDITMSG

并按下表在ClassWizardCCSockClientDlg添加量。

 

Control ID              Type              Member

   

IDC_EDITMSG           CEdit              m_MSG

IDC_LISTMSG              ClistBox              m_MSGS

 

3 CAsyncSocketDoCallBack函数MFC消息,当一个网事件

DoCallBack函数按网事件型:FD_READFD_WRITEFD_ACCEPTFD_CONNECT

别调OnReceiveOnSendOnAcceptOnConnect函数。由于MFC些事件

理函数定义为虚函数,所以要生成一个新的C++,以重载这些函数,做法如下:

 

Public方式CAsyncSocket,生成新MySock

 

MySock添加虚函数OnReceiveOnConnectOnSend

 

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_AddrIDC_Port按下表在ClassWizardCAddrDlg添加量。

 

Control ID              Type              Member

 

IDC_Addr              CString              m_Addr

IDC_Port              Int              m_Port

 

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.GetWindowText

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

    m_clientSocket.AsyncSelect(FD_WRITE);

    m_MSG.SetWindowText("");

              }

}

 

12 IDD_CSOCKCLIENT_DIALOG对话框中的“关闭”按,添加以下代

 

void CCSockClientDlg::OnExit()

{

              //关闭Socket

m_clientSocket.ShutDown(2);

              //关闭对话

EndDialog(0);             

}

 

12.运行此目,时输入主机名或IP均可,CAsyncSocket会自动处理。

 

二.

 

Server端的程与Client端的似,下面主要介他的ListenAccept函数

 

1 建立一个CNewSocket,重CAsyncSocketOnReceiveOnSend函数,

如何行信息的示和送可以参考Client程序。本例中采用将收到信息原封不

动发回的方法来实现Echo功能,代如下

CNewSocket::OnReceiveint nErrorCOde

{

              m_nLength=Receivem_szBuffersizeofm_szBuffer),0);

              // 直接转发消息

AsyncSelectFD_WRITE);

}

 

CNewSocket::OnSendint nErrorCode

{

              Sendm_szBufferm_nLength0);

}

 

2 建立一个CMyServerSocket,重CAsyncSocketOnAccept函数代如下

 

MyServerSocket.h中声明

public:

CNewSocket* m_pSocket

 

void CMyServerSocket::OnAcceptint nErrorCode

{

              //听到求,Accept函数

              CNewSocket* pSocket = new CNewSocket();

              if Accept*pSocket))

              {

    pSocket- >AsyncSelectFD_READ);

m_pSocket=pSocket

              }

              else

    delete pSocket

}

 

3 为对话框添加一个“听”按,添加如下代

 

CsockServerDlg.ccp中声明

public

              CMyServerSocket m_srvrSocket;

void CCSockServerDlg::OnListen()

{

              if m_srvrSocket.m_hSocket==INVALID_SOCKET

              {

    BOOL bFlag=m_srvrSocket.Create

       (UserPortSOCK_STREAMFD_ACCEPT)

    if (!bFlag

    {

                  AfxMessageBox(“Socket Error!”);

                  M_srvrSocket.Close();

                  PostQuitMessage0);

                  Return

    }

              }

//“听”成功,等待

if (!m_srvrSocketListen1))

{

    int nErrorCode = m_srvrSocket.GetLastError();

    if nError=WSAEWOULDBLOCK

    {

                  AfxMessageBox(“Socket Error!”);

                  M_srvrSocket.Close();

                  PostQuitMessage0);

                  Return

    }

              }

}

 

4 目前程序只能实现Echo功能,将信息原封不转发,若能将Accept中由

CNewSocket* pSocket = new CNewSocket();得到的Socket存入一个

CList或一个数中,便像Client端那所有的写控制。

 

三. 总结

 

CAsyncSocket类为使用Socket提供了极大方便。建立SocketWSAStartup

程和bind程被化成Create程,IP地址转换、主机名和IP地址

程中复杂型都被化成字符串和整数操作,特

CAsyncSocket的异特点,完全可以替代繁线程操作。MFC提供了大量的

类库,我若能灵活的使用他,便会大大提高程的效率。

posted on 2009-09-30 12:56  大钟  阅读(432)  评论(0)    收藏  举报