网络聊天程序的设计和实现报告.docx
《网络聊天程序的设计和实现报告.docx》由会员分享,可在线阅读,更多相关《网络聊天程序的设计和实现报告.docx(22页珍藏版)》请在冰豆网上搜索。
网络聊天程序的设计和实现报告
程序设计实践
设
计
报
告
课题名称:
网络聊天程序的设计和实现
学生姓名:
班 级:
班内序号:
17
学 号:
日 期:
2014.5.25
1)
课题概述
1.1课题目标和主要内容
主要内容和目标:
(1)按实验步骤使用VC++设计出程序,在此的基础上用VC++或其他工具设计出一个能实现两个人及以上人次聊天的网络程序。
(2)熟悉VisualC++的基本操作;掌握最基本的Client/Server(客户机/服务器)模式的网络编程技术,并在此基础上实现更为复杂的网络编程;基本了解基于对话框的windows应用程序的编写过程;对于WindowsSocket编程建立初步概念。
使用的开发平台:
VC2013
采用的主要工具:
MFC应用程序
1.2系统的主要功能
功能表:
1.建立服务器:
程序运行后,可以输入IP地址和端口号后建立服务器,用于监听信息。
2.实现客户端功能:
程序运行后,可以输入IP地址和端口号,连入服务器,进入聊天室聊天。
3.聊天功能:
进入聊天室的客户可以给自己取昵称,然后进行多人聊天。
界面可以输入聊天内容、昵称,可以显示聊天信息。
2)系统设计
2.1系统总体框架
系统框架图:
系统在输入IP和端口之后,可以建立服务器。
再打开一个程序作为客户端,输入IP和端口,连接进入服务器聊天室可以进行多人聊天。
2.2系统详细设计
2.2.1 模块划分图及描述
a)服务器监听模块:
添加一个基于CSocket的CserverSocket类,用于监听套接字。
其中CSocket是CAsyncSocket类的派生类,它们都是从CObject类继承下来的。
CSocket类是更高层次的网络接口抽象。
在服务器端,需要先用指定端口创建套接字,然后调用Listen()函数对制定连接端口进行监听,再创建一个空的CSocket对象。
收到请求后,调用Accept()函数对客户端的连接请求进行接收。
具体过程中,需要先添加成员变量和初始化函数声明。
然后需要重载OnAccept函数。
b)通信类模块
该部分主要用于创建客户端程序以及数据的传输,其实现方式原理如下:
i.客户端程序:
首先调用系统的Create()函数,用缺省的端口创建套接字;然后需要使用函数Connect()连接指定地址的服务器。
ii.数据传输:
该部分主要实现信息的传输、接受和处理。
首先创建与CSocket类的对象相连接的CSocketFile类对象,再创建与CSocketFile类的对象相连接的CArchive类对象,用于储存将要发送的数据,再创建与CSocketFile类的对象相连接的CArchive类对象,用于存储接收数据,最后只需要发送和接收数据。
具体实现方式为:
1.添加用于发送、接收和存储的成员变量以及初始化函数声明。
2.添加用于发送消息的SendMessage()函数,添加关闭套接字的函数CloseSocket()。
3.添加函数static int GetIpAddress()函数获取本地IP地址。
4.重载函数OnClose(),OnReceive(),分别用于服务器处理关闭套接字以及接收数据。
c)信息模块:
为项目添加基于CObject类的CMessg类,主要用于保存数据。
核心包括定义CString类型的变量m_strText,另外需要修改构造函数和Serialize函数。
d)窗口界面模块:
首先创建一个基于对话框的项目,再设计对话框:
添加一个ListBox控件显示所有聊天内容,并为其关联Clistbox类型的成员变量;添加一个EditBox控件输入发送聊天信息,并为其关联CString类型成员变量;添加一个IP控件输入服务器地址,并为其关联IP控件类型成员变量;添加一个EditBox类型控件输入服务器端口,并为其关联UNIT类型的成员变量;添加一个EditBox类型控件输入用户昵称,并为其关联一个CString类型成员变量;对吼添加三个按钮分别表示“发送消息”、“建立服务”和“连接服务器”,设置好各自的ID。
在对窗口的处理中,需要实现以下几点:
1.为对话框类中添加实现处理连接和处理断开连接的函数ProcessAccert()和CloseSessionSocket().
2.实现对相关变量的初始化;
3.对三个按钮建立相关的消息函数,包括建立服务,连接和发送消息。
2.2.2类关系图及描述
本程序CAboutDlg类并没有太大变化,主要对其他类进行分析:
CClientSocket类成员表:
名称
属性
说明
CClientSocket:
:
~CClientSocket
成员函数
析构函数
CClientSocket:
:
CClientSocket
成员函数
构造函数
CClientSocket:
:
CloseSocket
成员函数
关闭套接字
CClientSocket:
:
GetIpAddress
成员函数
获取本地IP
CClientSocket:
:
Init
成员函数
初始化
CClientSocket:
:
OnClose
成员函数
关闭连接
CClientSocket:
:
OnReceive
成员函数
接受数据
CClientSocket:
:
SendMessage
成员函数
发送数据
CClientSocket:
:
m_aSessionIn
成员变量
数据输入
CClientSocket:
:
m_aSessionOut
成员变量
数据接收
CClientSocket:
:
m_bClose
成员变量
关闭连接的BOOL型变量
CClientSocket:
:
m_bInit
成员变量
初始化变量
CClientSocket:
:
m_dlg
对象指针
用于进行操作的指针
CClientSocket:
:
m_sfSocketFile
指针
用于储存的指针
Cmessg类成员表:
名称
属性
说明
CMessg:
:
~CMessg
成员函数
析构函数
CMessg:
:
CMessg
成员函数
构造函数
CMessg:
:
Serialize
成员函数
控制数据输入和输出
CMessg:
:
from
成员变量
用户昵称,显示数据来源
CMessg:
:
m_strText
成员变量
输入聊天内容
CMessg:
:
to
成员变量
用户昵称,显示数据对象
CServerSocket类成员表:
名称
属性
说明
CServerSocket:
:
~CServerSocket
成员函数
析构函数
CServerSocket:
:
CServerSocket
成员函数
构造函数
CServerSocket:
:
Init
成员函数
服务器初始化
CServerSocket:
:
OnAccept
成员函数
重载后用于接收连接
CServerSocket:
:
m_dlg
对象指针
实现操作
CServerSocket:
:
m_uPort
成员变量
端口号
CSimpleChatDlg类成员表:
名称
属性
说明
CSimpleChatDlg:
:
CloseSessionSocket
成员函数
处理断开连接
CSimpleChatDlg:
:
CSimpleChatDlg
成员函数
构造函数
CSimpleChatDlg:
:
OnBnClickedConnect
成员函数
点击后连接服务器
CSimpleChatDlg:
:
OnBnClickedSendMessage
成员函数
点击后发送数据
CSimpleChatDlg:
:
OnBnClickedSetServer
成员函数
点击后建立服务器
CSimpleChatDlg:
:
OnInitDialog
成员函数
初始化对话框
CSimpleChatDlg:
:
ProcessPendingAccept
成员函数
处理连接
CSimpleChatDlg:
:
m_bClient
成员变量
BOOL类型记录连接
CSimpleChatDlg:
:
m_bInit
成员变量
BOOL类型记录是否初始化
CSimpleChatDlg:
:
m_clientsocket
对象名
套接字对象
CSimpleChatDlg:
:
m_connectionList
成员变量
连接者清单
CSimpleChatDlg:
:
m_name
成员变量
显示连接着昵称
CSimpleChatDlg:
:
m_pListenSocket
成员变量
服务器套接字
CSimpleChatDlg:
:
m_srvIP
成员变量
记录输入的IP地址
CSimpleChatDlg:
:
m_srvMessage
成员变量
显示聊天内容的控件变量
CSimpleChatDlg:
:
m_strMessage
成员变量
输入信息的控件变量
2.2.3程序流程图及描述
整个聊天室工作状态如上图。
2.3关键算法分析
函数一:
Init(UINT port,CSimpleChatDlg*dlg)//初始化服务器函数
BOOLCServerSocket:
:
Init(UINTport,CSimpleChatDlg* dlg)
{
ﻩm_uPort=port;
ﻩﻩm_dlg=dlg;
ﻩif(Create(m_uPort)==FALSE)
ﻩ{
ﻩAfxMessageBox(_T("服务器创建错误!
"));
ﻩreturnFALSE;
ﻩﻩ}
ﻩif(this->Listen()==FALSE)
ﻩﻩ{
ﻩﻩAfxMessageBox(_T("服务器监听失败!
"));
returnFALSE;
ﻩﻩ}
ﻩﻩm_dlg->m_srvMessage.AddString(_T("服务器建立成功!
"));
ﻩﻩreturn TRUE;
}
函数二:
OnClose(int nErrorCode)//关闭连接
void CClientSocket:
:
OnClose(intnErrorCode)
{
ﻩ//TODO:
在此添加专用代码和/或调用基类
ﻩm_bClose=true;
ﻩCloseSocket();
ﻩm_dlg->CloseSessionSocket();
ﻩCSocket:
:
OnClose(nErrorCode);
}
函数三:
CloseSocket()//关闭套接字
void CClientSocket:
:
CloseSocket()
{
ﻩif(m_aSessionIn)
{
ﻩdeletem_aSessionIn;
ﻩm_aSessionIn=NULL;
ﻩ}
if(m_aSessionOut)
ﻩ{
ﻩdeletem_aSessionOut;
ﻩﻩm_aSessionOut=NULL;
}
if(m_sfSocketFile)
{
deletem_aSessionOut;
m_sfSocketFile=NULL;
}
Close();
m_bInit=false;
m_bClose=true;
}
函数四:
OnReceive(intnErrorCode)//接收数据
voidCClientSocket:
:
OnReceive(intnErrorCode)
{
ﻩ//TODO:
在此添加专用代码和/或调用基类
do
ﻩ{
ﻩCMessg temp;
temp.Serialize(*m_aSessionIn);
ﻩﻩm_dlg->m_srvMessage.InsertString(0,temp.from+_T("说:
")+temp.m_strText);
ﻩ//m_dlg->m_namelist.InsertString(0, temp.from);
ﻩif(!
m_dlg->m_bClient)//服务器
ﻩ{
ﻩfor(POSITION pos=m_dlg->m_connectionList.GetHeadPosition();pos!
=NULL;)
ﻩﻩ{
ﻩﻩﻩCClientSocket*t= (CClientSocket*)m_dlg->m_connectionList.GetNext(pos);
ﻩif(t->m_hSocket!
=this->m_hSocket)
ﻩﻩt->SendMessage(&temp);
ﻩ}
ﻩ}
ﻩ}while(!
m_aSessionIn->IsBufferEmpty());ﻩ
m_dlg->UpdateData(false);
ﻩCSocket:
:
OnReceive(nErrorCode);
}
函数五:
GetIpAddress(const CString&sHostName,BYTE &f0,BYTE&f1,BYTE&f2,BYTE&f3)//获取本地IP
int CClientSocket:
:
GetIpAddress(constCString&sHostName,BYTE&f0,BYTE &f1,BYTE&f2,BYTE&f3)
{
structhostent FAR *lpHostEnt=gethostbyname((char*)&sHostName);
ﻩif(lpHostEnt==NULL)//错误
ﻩ{
f0=f1=f2=f3=0;
ﻩﻩreturnGetLastError();
}ﻩ
LPSTRlpAddr=lpHostEnt->h_addr_list[0];
if(lpAddr) //获取IP
ﻩ{
ﻩstructin_addr inAddr;
memmove(&inAddr,lpAddr,4);
f0=inAddr.S_un.S_un_b.s_b1;
ﻩf1=inAddr.S_un.S_un_b.s_b2;
f2=inAddr.S_un.S_un_b.s_b3;
ﻩf3=inAddr.S_un.S_un_b.s_b4;
ﻩ}
return0;
}
函数六:
OnBnClickedConnect()//连接服务器
voidCSimpleChatDlg:
:
OnBnClickedConnect()
{
//TODO:
在此添加控件通知处理程序代码
if(!
m_bInit)
{
ﻩBYTEf0,f1,f2,f3;
ﻩm_srvIP.GetAddress(f0,f1,f2,f3);
ﻩCStringip;
ﻩip.Format(_T("%d.%d.%d.%d"),f0,f1,f2,f3);
ﻩm_bClient=true;
ﻩm_clientsocket.Create();
ﻩif(m_clientsocket.Connect(ip,GetDlgItemInt(IDC_PORT)))
ﻩ{
ﻩﻩm_clientsocket.Init(this);
ﻩm_srvMessage.AddString(_T("连接成功!
"));
ﻩ//m_namelist.InsertString(0, m_name);
ﻩﻩm_bInit=true;
ﻩﻩ}
else
ﻩ{
ﻩﻩﻩm_clientsocket.Close();
ﻩﻩﻩAfxMessageBox(_T("连接失败!
"));
ﻩ//m_namelist.InsertString(0,m_name);
ﻩﻩm_bInit=false;
ﻩ}
ﻩ}
}
函数七:
OnBnClickedSendMessage()//点击发送消息
voidCSimpleChatDlg:
:
OnBnClickedSendMessage()
{
ﻩ//TODO:
在此添加控件通知处理程序代码
ﻩUpdateData();
ﻩif(!
m_bInit)
{
AfxMessageBox(_T("没有连接到服务器!
"));
ﻩﻩreturn;
ﻩ}
ﻩCMessg msg;
msg.m_strText=m_strMessage;
ﻩmsg.from= m_name;
CStringout;
ﻩif(!
m_bClient)
ﻩ{
ﻩout=msg.from;
out+="说:
";
ﻩﻩout +=msg.m_strText;
ﻩm_srvMessage.InsertString(0, out);
//m_namelist.InsertString(0,msg.from);
POSITIONpos;
ﻩﻩfor(pos=m_connectionList.GetHeadPosition();pos!
=NULL;)
ﻩ{
ﻩCClientSocket*t=(CClientSocket*)m_connectionList.GetNext(pos);
ﻩt->SendMessage(&msg);
ﻩﻩ}
}
else
{
ﻩout=msg.from;
ﻩout+="说:
";
out+= msg.m_strText;
ﻩm_srvMessage.InsertString(0,out);
ﻩ//m_namelist.InsertString(0,msg.from);
m_clientsocket.SendMessage(&msg);
ﻩ}
ﻩm_strMessage=_T("");
ﻩUpdateData(false);
}
函数八:
OnBnClickedSetServer()//建立服务器
voidCSimpleChatDlg:
:
OnBnClickedSetServer()
{
ﻩ// TODO:
在此添加控件通知处理程序代码
if(!
m_bInit)
ﻩ{
ﻩm_bClient=false;
m_bInit=true;
ﻩif(m_pListenSocket.Init(GetDlgItemInt(IDC_PORT),this)==FALSE)
ﻩ{
ﻩﻩm_bInit=false;
ﻩreturn;
ﻩ}
}
}
函数九:
ProcessPendingAccept()//处理链接
void CSimpleChatDlg:
:
ProcessPendingAccept()
{
ﻩCClientSocket*pSocket=newCClientSocket();
if(m_pListenSocket.Accept(*pSocket))
ﻩ{
ﻩﻩCMessgmsg;
ﻩmsg.m_strText=_T("一个游客进入聊天室了");
ﻩm_srvMessage.InsertString(0,_T("一个游客进入聊天室了"));
POSITIONpos;
ﻩfor(pos=m_connectionList.GetHeadPosition();pos!
=NULL;)
ﻩﻩ{
ﻩCClientSocket * t=(CClientSocket*)m_connectionList.GetNext(pos);
ﻩt->SendMessage(&msg);
ﻩ}
ﻩpSocket->Init(this);
ﻩm_connectionList.AddTail(pSocket);
}
ﻩelse
deletepSocket;
}
3.程序运行结果分析
图一:
建立服务器
图二:
客户端连接
图三:
服务器端显示
图四:
自由聊天展示
4.总结
4.1课题的难点和关键点
难点:
1.对windows套接字的使用;
2.对各种类成员函数调用;
3.需要使用面向对象的编程,编写较为复杂。
关键点:
利用MFC提供的CSocket类来创建聊天工具,可以被动地接收网友聊天请求,还能主动提出聊天请求。
应将聊天室系统分为两部分:
服务器和客户端,需要先启动服务器,指定端口号,同时取一个网名,客户端则需要输入IP和端口号登录服务器,取一个网名与服务器连接,然后再简单聊天室中聊天。
4.2本课题的评价
套接字编程接口已经成为目前进行网络通信的实际标准,我们在使用套接字进行开发的过程中,可以不必过多考虑底层协议的具体实现,这对于我们来讲是优势。
套接字编程接口也有一定不足,比如:
函数众多,调用频繁,不利于基于面向对象的开发等。
4.3心得体会
通过实验加深对VC2013的了解和掌握,对该程序有了更深刻的认识。
学习了CAsyncSocket和CSocket类进行网络编程,能使我在今后的学习中开发出一片新的天地,丰富了我的知识,开拓了我的视野,有利于在今后的学习中举一反三,将MFC作为一项基本的工具,投入到学习生活之中,让我对自己的未来充满信心。
5.参考文献
[1]《VisualC++.NET2005 中文版基础与实践教程》电子工业出版社
[2]《Visual C++.NET程序设计》 清华大学出版社
[3]《计算机网络——简单聊天程序的设计与实现》 某学校实验