使用MFC快速实现网络编程 CAsyncSocket

翻译|其它|编辑:郝浩|2007-09-28 16:41:36.000|阅读 1546 次

概述:

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>

随着计算机网络化的深入,计算机网络编程在程序设计的过程中变得日益重要。由于  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  类添加变量。

Control ID
Type Member
IDC_EDITMSG
CEdit m_MSGIDC_LISTMSG
ClistBox
m_MSGS

---- 3 CAsyncSocket  类用  DoCallBack  函数处理  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  按下表在  ClassWizard  中为  CAddrDlg  类添加变量。 Control ID Type MemberIDC_Addr CString m_AddrIDC_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; //
默认端口1088m_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>10SetTimer(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() {
//
关闭  Socketm_clientSocket.ShutDown(2); //关闭对话框  EndDialog(0); }

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

----二. 服务端

----Server  端的编程与  Client  端的类似,下面主要介绍他的  Listen    Accept  函数

----1 建立一个  CNewSocket  类,重载  CAsyncSocket  类的  OnReceiveOnSend  函数,

如何进行信息的显示和发送可以参考  Client  程序。本例中采用将收到信息原封不动发回的方法来实现 Echo  功能,代码如下  CNewSocket::OnReceiveint nErrorCOde{
m_nLength=Receive
m_szBuffersizeofm_szBuffer),0);
//
直接转发消息  AsyncSelectFD_WRITE);}CNewSocket::OnSendint nErrorCode{ Sendm_szBufferm_nLength0);}

----2 建立一个  CMyServerSocket  类,重载  CAsyncSocket  类的  OnAccept  函数代码如下

----  MyServerSocket.h  中声明变量  public:CNewSocket* m_pSocket
void CMyServerSocket
::OnAcceptint nErrorCode{
//
侦听到连接请求,调用  Accept  函数
CNewSocket* pSocket = new CNewSocket
();
if
Accept*pSocket)) {
pSocket- >AsyncSelect
FD_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
(UserPort
SOCK_STREAMFD_ACCEPT)
if
(!bFlag { AfxMessageBox“Socket Error);
M_srvrSocket.Close
();
PostQuitMessage
0);
Return
} }
//“
侦听成功,等待连接请求  if (!m_srvrSocketListen1)){
int nErrorCode = m_srvrSocket.GetLastError
();
if
nError=WSAEWOULDBLOCK
{
AfxMessageBox
“Socket Error);
M_srvrSocket.Close
();
PostQuitMessage
0);
Return

} }}

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

CNewSocket* pSocket = new CNewSocket();得到的  Socket  指针存入一个  CList  或一个数组中,便像  Client  端那样,对所有的连接进行读写控制。

----三. 总结

----CAsyncSocket  类为我们使用  Socket  提供了极大方便。建立  Socket    WSAStartup  过程和  bind  过程被简化成为  Create  过程,IP  地址类型转换、主机名和  IP  地址转换的过程中许多复杂的变量类型都被简化成字符串和整数操作,特别是  CAsyncSocket  类的异步特点,完全可以替代繁琐的线程操作。MFC  提供了大量的类库,我们若能灵活的使用他们,便会大大提高编程的效率。 


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com

文章转载自:CSDN

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP