用MFC CSocket类实现的网络聊天室.docx
- 文档编号:30743686
- 上传时间:2023-08-20
- 格式:DOCX
- 页数:36
- 大小:761.72KB
用MFC CSocket类实现的网络聊天室.docx
《用MFC CSocket类实现的网络聊天室.docx》由会员分享,可在线阅读,更多相关《用MFC CSocket类实现的网络聊天室.docx(36页珍藏版)》请在冰豆网上搜索。
用MFCCSocket类实现的网络聊天室
用CSocket类实现的网络聊天室
一、服务器端应用程序(Ts.exe)的实现步骤
1、建立“基于对话框”类型的MFC项目,项目名称Ts。
按照向导进行设置,当打开“高级功能”设置页面时,勾选“Windows套接字”选项,如图所示,其他步骤采用默认值即可。
2、界面控件设计。
在对话框资源编辑窗口中设计如图所示界面,界面上控件的属性按照下表设置。
序号
控件类型
ID
属性
值
1
IDC_STATIC
Caption
监听端口号:
2
IDC_EDIT_PORT
3
IDC_BUTTON_LISTEN
Caption
监听
4
IDOK
Caption
停止服务
Disabled
True
5
ID_LIST_MSG
Sort
False
6
IDC_STATIC_NUM
Caption
聊天室在线人数:
0
3、打开“MFC类向导”,按照下表设置控件在CTsDlg类中的成员变量,效果如图所示;
控件ID
成员变量名称
类别
变量类型
IDC_STATIC_NUM
m_strNum
Value
CString
IDC_EDIT_PORT
m_nPort
Value
UINT
IDC_BUTTON_LISTEN
m_btnListen
Control
CButton
IDOK
m_btnClose
Control
CButton
IDC_LIST_MSG
m_listMsg
Control
CListBox
4、选择菜单“项目”->“添加类”,添加一个“MFC类”:
CMsg,基类选择CObject,如图所示。
为CMsg添加两个成员变量:
CStringm_strText;//字符串成员,消息文本
BOOLm_bClose;//退出聊天室标识
接下来,在Msg.h文件中添加DECLARE_SERIAL宏,在Msg.cpp文件中添加IMPLEMENT_SERIAL宏;最后,使用MFC类向导添加虚函数Serialize(),如图所示。
CMsg类的代码如下:
//Msg.h
#pragmaonce
//CMsg命令目标
classCMsg:
publicCObject
{
DECLARE_SERIAL(CMsg)
public:
CMsg();
virtual~CMsg();
public:
CStringm_strText;//字符串成员,消息文本
BOOLm_bClose;//退出聊天室标识
virtualvoidSerialize(CArchive&ar);
};
//Msg.cpp:
实º¦Ì现?
文?
件t
#include"stdafx.h"
#include"Ts.h"
#include"Msg.h"
//CMsg
IMPLEMENT_SERIAL(CMsg,CObject,0)
CMsg:
:
CMsg()
{
}
CMsg:
:
~CMsg()
{
}
voidCMsg:
:
Serialize(CArchive&ar)
{
if(ar.IsStoring())
{//storingcode
ar< } else {//loadingcode ar>>m_strText>>m_bClose; } } 5、从CSocket类派生两个套接字类,一个名为CLSocket,专用于监听客户机端的连接请求;另一个名为CCSocket,用于与客户机建立连接并交换数据。 操作步骤为: 选择菜单“项目”->“添加类”,在弹出的对话框中选择“MFC类”项,单击“添加”按钮;然后在弹出的“MFC添加类向导”窗口中输入类名,并选择基类为CSocket,如图所示。 6、使用“MFC类向导”为CLSocket类添加OnAccept事件处理函数,操作如图所示。 7、使用“MFC类向导”为CCSocket类添加OnReceive事件处理函数,操作如下图所示。 8、分别为CLSocket和CCSocket类添加一个指向对话框类的指针变量: CTsDlg*m_pDlg; 为避免对话框类与套接字类交叉引用,在类的定义前添加 classCTsDlg; 修改CLSocket和CCSocket类的构造函数,添加一个CTsDlg*类型的参数。 如图所示。 在LSocket.cpp中添加头文件的引用,并完成CLSocket类构造函数的修改: #include"TsDlg.h" CLSocket: : CLSocket(CTsDlg*pDlg) { this->m_pDlg=pDlg; } 同样,在CSocket.cpp中添加头文件的引用,并完成CCSocket类构造函数的修改: #include"TsDlg.h" CCSocket: : CCSocket(CTsDlg*pDlg) { this->m_pDlg=pDlg; } 9、为CCSocket类添加成员变量和成员函数的定义(CSocket.h)。 成员变量: CSocketFile*m_pFile;//CSocketFile对象指针变量 CArchive*m_pArIn;//用于输出的CArchive对象指针 CArchive*m_pArOut;//用于输出的CArchive对象指针 成员函数: voidReceiveMsg(CMsg*pMsg);//接收消息 voidSendMsg(CMsg*pMsg);//发送消息 voidInitialize();//初始化 在CSocket.cpp中,实现这三个成员函数,并修改CCSocket类的析构函数: voidCCSocket: : Initialize() { m_pFile=newCSocketFile(this,TRUE); m_pArIn=newCArchive(m_pFile,CArchive: : load); m_pArOut=newCArchive(m_pFile,CArchive: : store); } voidCCSocket: : SendMsg(CMsg*pMsg) { if(m_pArOut! =NULL) { pMsg->Serialize(*m_pArOut); m_pArOut->Flush(); } } voidCCSocket: : ReceiveMsg(CMsg*pMsg) { pMsg->Serialize(*m_pArIn); } CCSocket: : ~CCSocket() { m_pDlg=NULL; if(m_pArOut! =NULL){m_pArOut->Close();deletem_pArOut;m_pArOut=NULL;} if(m_pArIn! =NULL){m_pArIn->Close();deletem_pArIn;m_pArIn=NULL;} if(m_pFile! =NULL){m_pFile->Close();deletem_pFile;m_pFile=NULL;} } 10、在TsDlg.h文件(CTsDlg类的定义文件)中添加下面两个文件的引用: #include"CSocket.h" #include"LSocket.h" 并添加成员变量: CLSocket*m_pLSocket;//监听套接字指针 CPtrListm_connList;//连接列表 和成员函数的声明: voidbackClient(CMsg*pMsg);//向聊天室所有客户机转发消息 voidOnReceive(CCSocket*pSocket);//获取客户机消息 voidOnAccept();//接受连接请求 在TsDlg.cpp中,实现这三个成员函数: voidCTsDlg: : OnAccept() { CCSocket*pSocket=newCCSocket(this); if(m_pLSocket->Accept(*pSocket)) { pSocket->Initialize(); m_connList.AddTail(pSocket); CStringstrTemp; strTemp.Format(L"在线人数: %d",m_connList.GetCount()); m_strNum=strTemp; UpdateData(FALSE); } else deletepSocket; } voidCTsDlg: : OnReceive(CCSocket*pSocket) { staticCMsgmsg; do { pSocket->ReceiveMsg(&msg); m_listMsg.AddString(msg.m_strText); backClient(&msg); if(msg.m_bClose) { pSocket->Close(); POSITIONpos,temp; CCSocket*pTemp; for(pos=m_connList.GetHeadPosition();pos! =NULL;) { temp=pos; pTemp=(CCSocket*)m_connList.GetNext(pos); if(pTemp==pSocket) { m_connList.RemoveAt(temp); CStringstrTemp; strTemp.Format(L"在线人数: %d",m_connList.GetCount()); m_strNum=strTemp; UpdateData(FALSE); } } deletepSocket; break; } }while(! pSocket->m_pArIn->IsBufferEmpty()); } voidCTsDlg: : backClient(CMsg*pMsg) { CCSocket*pSocket; for(POSITIONpos=m_connList.GetHeadPosition();pos! =NULL;) { pSocket=(CCSocket*)m_connList.GetNext(pos); pSocket->SendMsg(pMsg); } } 11、完成CLSocket类的OnAccept()函数的代码(第6步添加的虚函数): voidCLSocket: : OnAccept(intnErrorCode) { CSocket: : OnAccept(nErrorCode); if(m_pDlg! =NULL)m_pDlg->OnAccept(); } 完成CCSocket类的OnAccept()函数的代码(第7步添加的虚函数): voidCCSocket: : OnReceive(intnErrorCode) { CSocket: : OnReceive(nErrorCode); m_pDlg->OnReceive(this); } 12、为对话框CTsDlg的“监听”和“停止服务”两个按钮添加消息响应函数。 (方法可以在对话框资源编辑窗口双击对应按钮,或使用类向导) voidCTsDlg: : OnBnClickedButtonListen() { //TODO: Addyourcontrolnotificationhandlercodehere UpdateData(TRUE); m_pLSocket=newCLSocket(this); if(! m_pLSocket->Create(m_nPort)) { deletem_pLSocket; m_pLSocket=NULL; AfxMessageBox(L"创建监听套接字错误"); return; } if(! m_pLSocket->Listen()) { deletem_pLSocket; m_pLSocket=NULL; AfxMessageBox(L"启动监听错误"); return; } GetDlgItem(IDC_EDIT_PORT)->EnableWindow(FALSE); GetDlgItem(IDC_BUTTON_LISTEN)->EnableWindow(FALSE); GetDlgItem(IDOK)->EnableWindow(TRUE); } voidCTsDlg: : OnBnClickedOk() { //TODO: Addyourcontrolnotificationhandlercodehere CMsgmsg; msg.m_strText=L"服务器终止服务"; deletem_pLSocket; m_pLSocket=NULL; CCSocket*pSocket; while(! m_connList.IsEmpty()) { pSocket=(CCSocket*)m_connList.RemoveHead(); pSocket->SendMsg(&msg); deletepSocket; } while(m_listMsg.GetCount()! =0) m_listMsg.DeleteString(0); GetDlgItem(IDC_EDIT_PORT)->EnableWindow(TRUE); GetDlgItem(IDC_BUTTON_LISTEN)->EnableWindow(TRUE); GetDlgItem(IDOK)->EnableWindow(FALSE); } 13、最后,在CTsdlg类的OninitDialog()函数中添加如下初始化代码: m_nPort=8000; UpdateData(FALSE); GetDlgItem(IDOK)->EnableWindow(FALSE); 效果如下: 二、客户端应用程序(Tc.exe)的实现步骤 1、建立“基于对话框”类型的MFC项目,项目名称Tc。 按照向导进行设置,当打开“高级功能”设置页面时,勾选“Windows套接字”选项,如图所示,其他步骤采用默认值即可。 2、界面控件设计。 在对话框资源编辑窗口中设计如图所示界面,界面上控件的属性按照下表设置。 序号 控件类型 ID 属性 值 1 IDC_EDIT_CNAME 2 IDC_EDIT_SNAME 3 IDC_EDIT_PORT 4 IDC_EDIT_MSG 5 ID_LIST_MSG Sort False 6 IDC_BUTTON_CLOSE Caption 退出 7 IDC_BUTTON_CONN Caption 连接 8 IDOK Caption 发送 9 IDC_STATIC Caption 客户名: 10 IDC_STATIC Caption 服务器名: 11 IDC_STATIC Caption 端口: 12 IDC_STATIC Caption 消息: 3、打开“MFC类向导”,按照下表设置控件在CTsDlg类中的成员变量,效果如图所示; 控件ID 成员变量名称 类别 变量类型 IDC_EDIT_CNAME m_strCName Value CString IDC_EDIT_SNAME m_strSName Value CString IDC_EDIT_PORT m_nPort Value UINT IDC_EDIT_MSG m_strMsg Value CString IDC_BUTTON_CONN m_btnConn Control CButton IDOK m_Send Control CButton ID_BUTTON_CLOSE m_btnClose Control CButton IDC_LIST_MSG m_listMsg Control CListBox 4、创建CMsg类。 方法同服务器端应用程序(Ts.exe)步骤4。 也可以直接将服务器端应用程序的CMsg类添加到当前工程中,方法为: 1)首先将Msg.h和Msg.cpp两个文件复制到当前工程目录下; 2)然后选择菜单“项目”->“添加现有项”,在弹出的对话框中选中这两个文件,单击“添加”按钮,如图所示; 3)这时在类视图中会出现CMsg类,如图所示。 4)打开CMsg类的实现文件(Msg.cpp),将其中的头文件引用: #include"Ts.h" 改为: #include"Tc.h" 5、从CSocket类派生一个套接字类CCSocket,用于与客户机建立连接并交换数据。 如图所示: 6、使用类向导,为CCSocket类添加OnReceive事件处理函数,如图所示。 8、为CCSocket类添加一个指向对话框类的指针变量: CTcDlg*m_pDlg; 为避免对话框类与套接字类交叉引用,在类的定义前添加 classCTcDlg; 修改CCSocket类的构造函数,添加一个CTcDlg*类型的参数。 如图所示。 在CSocket.cpp中添加头文件的引用,并完成CCSocket类构造函数的修改: #include"TcDlg.h" CCSocket: : CCSocket(CTcDlg*pDlg) { m_pDlg=pDlg; } 9、在TcDlg.h文件(CTsDlg类的定义文件)中添加下面的头文件引用: #include"CSocket.h" 并添加成员变量: CCSocket*m_pSocket;//套接字对象指针 CSocketFile*m_pFile;//CSoketFile对象指针 CArchive*m_pArchiveIn;//用于输入的CArchive对象 CArchive*m_pArchiveOut;//用于输出的CArchive对象 和成员函数的声明: voidOnReceive();//接收信息 voidReceiveMsg();//接收服务器发送来的消息 voidSendMsg(CString&strText,boolst);//向服务器发送消息 在TcDlg.cpp中,添加对Msg.h文件的引用和实现这三个成员函数: #include"Msg.h" voidCTcDlg: : OnReceive() { do{ ReceiveMsg(); if(m_pSocket==NULL)return; }while(! m_pArchiveIn->IsBufferEmpty()); } voidCTcDlg: : ReceiveMsg() { CMsgmsg; TRY { msg.Serialize(*m_pArchiveIn); m_listMsg.AddString(msg.m_strText); } CATCH(CFileException,e) { CStringstrTemp; strTemp=L"服¤t务? 器¡Â重? 置? 连¢? 接¨®! ê? 连¢? 接¨®关? 闭À? "; m_listMsg.AddString(strTemp); msg.m_bClose=TRUE; m_pArchiveOut->Abort(); deletem_pArchiveIn; m_pArchiveIn=NULL; deletem_pArchiveOut; m_pArchiveOut=NULL; deletem_pFile; m_pFile=NULL; deletem_pSocket; m_pSocket=NULL; } END_CATCH } voidCTcDlg: : SendMsg(CString&strText,boolst) { if(m_pArchiveOut! =NULL) { CMsgmsg; msg.m_strText=strText; msg.m_bClose=st; msg.Serialize(*m_pArchiveOut); m_pArchiveOut->Flush(); } } 10、为对话框CTcDlg的“退出”、“连接”和“发送”三个按钮添加消息响应函数。 (方法可以在对话框资源编辑窗口双击对应按钮,或使用类向导) voidCTcDlg: : OnBnClickedButtonConn() { //TODO: Addyourcontrolnotificationhandlercodehere UpdateData(TRUE); m_pSocket=newCCSocket(this); if(! m_pSocket->Create()) { deletem_pSocket; m_pSocket=NULL; AfxMessageBox(L"套接字创建错误"); return; } if(! m_pSocket->Connect(m_strSName,m_nPort)) { deletem_pSocket; m_pSocket=NULL; AfxMessageBox(L"无法连接到服务器"); return; } m_pFile=newCSocketFile(m_pSocket); m_pArchiveIn=newCArchive(m_pFile,CArchive: : load); m_pArchiveOut=newCArchive(m_pFile,CArchive: : store); UpdateData(TRUE); CStringstrTemp; strTemp=m_strCName+L": 进入聊天室"; SendMsg(strTemp,FALSE); GetDlgItem(IDC_EDIT_MSG)->EnableWindow(TRUE); GetDlgItem(IDOK)->EnableWindow(TRUE); GetDlgItem(IDC_BUTTON_CLOSE)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 用MFC CSocket类实现的网络聊天室 MFC CSocket 实现 网络 聊天室