CAsyncSocket编程 MFC
许多时候我们实现网络编程使用的是winsock api函数,虽然这些函数使用起来也很方便,很灵活,但是VC++的MFC类库中提供了CAsyncSocket这样一个套接字类,用它来实现socket编程会更方便。
1、服务器端 项目:CSockServer
Server端的编程与Client端的类似,下面主要介绍他的Listen及Accept函数
1. 建立一个CNewSocket类,重载CAsyncSocket类的OnReceive、OnSend函数,
如何进行信息的显示和发送可以参考Client程序。本例中采用将收到信息原封不动
发回的方法来实现Echo功能,代码如下
CNewSocket::OnReceive(int nErrorCOde){ m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0); // 直接转发消息AsyncSelect(FD_WRITE);}CNewSocket::OnSend(int nErrorCode){ Send(m_szBuffer,m_nLength,0);}
2. 建立一个CMyServerSocket类,重载CAsyncSocket类的OnAccept函数代码如下
void CMyServerSocket::OnAccept(int nErrorCode){ //侦听到连接请求,调用Accept函数 CNewSocket* pSocket = new CNewSocket(); if (Accept(*pSocket)) { pSocket- >AsyncSelect(FD_READ); m_pSocket=pSocket; } else delete pSocket;}
在MyServerSocket.h中声明变量public::CNewSocket* m_pSocket;
3. 对话框添加一个侦听按钮,添加如下代码
void CCSockServerDlg::OnListen(){ if (m_srvrSocket.m_hSocket==INVALID_SOCKET) { BOOL bFlag=m_srvrSocket.Create (UserPort,SOCK_STREAM,FD_ACCEPT); if (!bFlag) { AfxMessageBox(“Socket Error!”); M_srvrSocket.Close(); PostQuitMessage(0); Return; } } //“侦听”成功,等待连接请求if (!m_srvrSocket。Listen(1)){ int nErrorCode = m_srvrSocket.GetLastError(); if (nError!=WSAEWOULDBLOCK) { AfxMessageBox(“Socket Error!”); M_srvrSocket.Close(); PostQuitMessage(0); Return; } }}
在CsockServerDlg.ccp中声明变量public: CMyServerSocket m_srvrSocket;
4. 目前程序只能实现Echo功能,将信息原封不动的转发,若能将Accept中由
CNewSocket* pSocket = new CNewSocket();
得到的Socket指针存入一个CList或一个数组中,便像Client端那样,对所有的连接进行读写控制。
2、客户端:
1. 创建项目CSockClient
2. 设计对话框
去掉OK和Cancle两个按钮,增加ID_Connect(连接)、ID_Send(发送)、ID_EXIT(关闭)按钮,添加ListBox控件IDC_LISTMSG和Edit控件IDC_EDITMSG,并按下表为为控件添加变量。
IDC_EDITMSG | CEdit | m_MSGIDC_LISTMSG |
CListBox | m_MSGS |
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.h中添加以下代码:
1 public: 2 // 是否连接 3 BOOL m_bConnected; 4 // 消息长度 5 UINT m_nLength; 6 // 消息缓冲区 7 char m_szBuffer[512];
5. 在MySock.cpp中重载各种函数
OnReceive、OnConnect、OnSend
6. 双击IDD_CSOCKCLIENT_DIALOG对话框中的连接按钮,添加以下代码
1 CCSockClientDlg::OnConnect() { 2 m_clientSocket.ShutDown(2); 3 m_clientSocket.m_hSocket=INVALID_SOCKET; 4 m_clientSocket.m_bConnected=FALSE; 5 CAddrDlg m_Dlg; //默认端口1088m_Dlg.m_Port=1088; 6 if (m_Dlg.DoModal()==IDOK && !m_Dlg.m_Addr.IsEmpty()) { 7 memcpy(m_szServerAdr,m_Dlg.m_Addr,sizeof(m_szServerAdr)); 8 m_szPort=m_Dlg.m_Port; //建立计时器,每1秒尝试连接一次,直到连上或TryCount>10SetTimer(1,1000,NULL); 9 TryCount=0; }}
7. 添加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);}
8. 双击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(""); }}
9. 双击IDD_CSOCKCLIENT_DIALOG对话框中的关闭按钮,添加以下代码
CCSockClientDlg::OnExit() { //关闭Socketm_clientSocket.ShutDown(2); //关闭对话框EndDialog(0); }
3、总结
CAsyncSocket类为我们使用Socket提供了极大方便。建立Socket的WSAStartup过程和bind过程被简化成为Create过程,
IP地址类型转换、主机名和IP地址转换的过程中许多复杂的变量类型都被简化成字符串和整数操作,特别是CAsyncSocket
类的异步特点,完全可以替代繁琐的线程操作。MFC提供了大量的类库,我们若能灵活的使用他们,便会大大提高编程的效
4、我的疑问
此文为转载,自己还没有实际的实验过,所以还没有什么疑问,
转载自:MFC网络编程学习