CAsyncSocket聊天程序
一、需求分析
如图1和图2,分别设计服务器端程序和客户端程序,单击客户端的“access server”按钮,可以连接到服务器端,单击客户端的“sendto”按钮,可以将编辑框中的文字发送的服务器端,并在服务器端对话框中的编辑框中显示,单击服务器端“Send”按钮,可以将服务器端对话框中的编辑框的内容发送到客户机端并显示在编辑框中。
通过此实验,验证基于CasyncSocket类建立服务器与客户机通信的实现机制。体验消息机制的优势。
图1、服务器端程序界面图2、客户机端程序界面
二、程序设计步骤
1、服务器端程序
(1)创建基于“基本对话框”的项目AsyncSer,注意选中“包含WOSA支持”;
(2)在对话框中删除“TODO:在这里设置对话框”文字提示,为对话框添加编辑框和命令按钮,为编辑框绑定control类型的变量m_edit,将命令按钮改名为“Send”;
(3)切换到类视图,为项目添加基于CasyncSocket类的新类,此步的目的是为了重载CasyncSocket类中的OnReceive()等函数,以实现根据消息来自动触发相关函数,实现数
据在服务器与客户机之间的传送与接收。
具体做法是:右击项目名称“AsyncSer classes”,在弹出的快捷菜单中单击“New Class。。。”
菜单项(图3),出现图4,选择所要新建类的类型为“MFC Class”,Name为CServerSocket,Base Class 为CAsyncSocket,即以CasyncSocket类为基类,派生新类CserverSocket(注意类名的大小写)。
图3、添加新类快捷菜单图4 “新建类”对话框
按同样的方法,为项目再添加一个以CAsyncSocket类为基类的新类CClientSocket。
说明:创建CServerSocket类的目的为了创建用来侦听的套接字,而创建CClientSocket类的目的为了创建用来和客户机连接并通信的套接字。因为侦听套接字的主要作用在于侦听,只需重载OnConnect函数即可,而连接套接字的主要功能在于数据的传送和接收,通常要重载OnReceive函数,所以习惯上要将侦听套接字和连接套接字分别由不同类来创建。
下面重载有关的函数:
对CServerSocket类,重载其OnAccept函数。按“Ctrl+W”键,弹出MFC ClassWizard 窗
(消息映射)选项卡,在Class Name:下拉列表框中选择CServerSocket,口(图5),选中“Message Maps”
可以看到,在Messages列表栏中列出了一些消息响应函数,这些函数都是基类CAsyncSocket类的消息响应函数,双击其中的:OnAccept,即可实现在CServerSocket类中重载CAsyncSocket类的OnAccept函数,注意,此时OnAccept函数还没有添加功能,我们将在下面的步骤中添加。
同样的方法,为CClientSocket类重载函数OnReceive函数。当然,其功能也在下面的步骤中添加。
图5 MFC ClassWizard 窗口
(4)为对话框类添加变量:先在类视图中右击对话框类CAsyncSerDlg,在弹出的快捷菜单中选择Add MemberV ariable,添加侦听套接字server,其类型为CServerSocket,添加连接套接字client,其类型为CClientSocket。添加字符数组buff[200],类型为char,用来存储接收或发送的数据。
(5)重载CServerSocket::OnAccept(int nErrorCode)函数。OnAccept函数在收到客户端程序的连接请求时会自动调用,此函数的调用意味着服务器已经收到客户端的连接请求,应该在此函数中应创建与客户端的连接,代码如下:
void CServerSocket::OnAccept(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
CAsyncSerDlg * dlg=(CAsyncSerDlg*)AfxGetApp()->GetMainWnd();
//上面代码的含义大家要想明白
Accept(dlg->client); //让client套接字与客户机建立连接,server套接字继续侦听。
CAsyncSocket::OnAccept(nErrorCode);
}
因为CServerSocket:类用到了
CAsyncSerDlg * dlg=(CAsyncSerDlg*)AfxGetApp()->GetMainWnd();,故应在CServerSocket:类中添加语句#include “asyncserdlg.h”,CClientSocket类也是如此。
(6)重载CClientSocket类的OnReceive函数。OnReceive函数在数据发送到后自动调用,此函数主要作用是接收数据。代码如下:
void CClientSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
CAsyncSerDlg * dlg=(CAsyncSerDlg*)AfxGetApp()->GetMainWnd();
Receive(dlg->buff,200,0);
dlg->m_edit.SetWindowText(dlg->buff);
CAsyncSocket::OnReceive(nErrorCode);
}
(7)为Send按钮定义函数:在资源视图中打开对话框,双击Send按钮,自动切换到代码编辑界面,输入以下代码
m_edit.GetWindowText(buff,200);
client.Send(buff,200,0);
在OnInitDialoge函数中,添加代码:
server.Create(3000);
server.Listen();
服务器端程序设计完成。
2、客户端程序设计
(1)创建基于“基本对话框”的项目AsyncClient,注意选中“包含WOSA支持”;
(2)在对话框中删除“TODO:在这里设置对话框”文字提示,为对话框添加编辑框和2个命令按钮,为编辑框绑定control类型的变量m_edit,将命令按钮1改名为“Access Server”,命令按钮2改名为“Send to”;
(3)为项目添加类CMySocket,派生自CAsyncSocket类,并重载OnReceive函数,以便有数据发过来时,接收数据并显示到对话框中的编辑框中,代码如下:
void CMySocket:: OnReceive (int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
CAsyncClientDlg *dlg=(CAsyncClientDlg *)AfxGetApp()->GetMainWnd();
Receive(dlg->buff,200,0);
dlg->m_edit.SetWindowText(dlg->buff);
CAsyncSocket::OnReceive(nErrorCode);
}
在CMySocket类中也要有#include “asyncClient.h”,不然CAsyncClientDlg *dlg=(CAsyncClientDlg *)AfxGetApp()->GetMainWnd();将在编译时出错。
(4)为对话框类CA yncClientDlg添加CMySocket类的对象client,用来与服务器建立连接。Char 类数据buff[200],用来存放收发的数据。
在OnInitDialog()函数中添加client.Create();
(5)为Access Server命令按钮创建函数,一般单击它时实现与服务器的连接,代码如下:
CString errcode;
if(client.Connect("127.0.0.1",3000))
m_edit.SetWindowText("连接成功");
else
{
errcode.Format("%d",GetLastError());
m_edit.SetWindowText(errcode);
}
为Sendto按钮创建函数,以实现单击此按钮时,将编辑框中的数据发送到服务器。代码如下:m_edit.GetWindowText(buff,200);
CString kk;
kk.Format("%d",client.Send(buff,200,0));
m_edit.SetWindowText(kk);