山东建筑大学课程设计.docx
- 文档编号:24459746
- 上传时间:2023-05-27
- 格式:DOCX
- 页数:37
- 大小:322.40KB
山东建筑大学课程设计.docx
《山东建筑大学课程设计.docx》由会员分享,可在线阅读,更多相关《山东建筑大学课程设计.docx(37页珍藏版)》请在冰豆网上搜索。
山东建筑大学课程设计
山东建筑大学
课程设计说明书(论文)
题目:
聊天程序的开发
课程:
VC++程序设计基础课程设计
院(部):
信息与电气工程学院
专业:
电子信息工程
班级:
学生姓名:
学号:
指导教师:
完成日期:
聊天程序
摘要
计算机网络技术发展至今已经大大超越了人们当初的预想,无论是人们日常的工作还是学习,我们都越来越多的依靠到互联网。
各种实时性的聊天娱乐软件也同时诞生,而且为我们的即时通讯带来了众多的方便,比如说大家所熟知的腾讯QQ、微软的MSN、移动的Fetion等,都是做的比较成功的实时聊天工具。
随着网络的日益普及,各种聊天工具也层出不穷,但当我们学习了《windows程序设计》这门课程之后,我们决定设计一个简单的聊天系统来巩固我们的学习。
接下来的课程设计就是针对一个简单的网络聊天程序,利用MFC为开发工具,实现基本的通讯功能。
在课程设计中,系统开发平台为WindowsXP,程序设计设计语言采用VisualC++,数据库采用Access,程序运行平台为Windows98/2000/XP。
关键词聊天软件;局域网;MFC;VisualC++;多线程
1引言
1.1课题背景及意义
当今世界正处于信息时代,计算机和通信网络是这一时代所谓“信息基础设施”。
在互联网相当普及的今天,在互联网上聊天对很多“网虫”来说已经是家常便饭了。
聊天室程序可以说是网上最简单的多点通信程序。
一个简单的聊天室,从程序员的观点来看就是在多个I/O端点之间实现多对多的通信。
基于SOCKET的局域网通信是一种灵活的、易于实现的、低成本的方法。
它可以运行在各种使用TCP/IP协议作为通讯协议的网络上。
而在SOCKETAPI的帮助下,开发基于SOCKET的局域网通信软件也是易于实现的。
1.2实验平台介绍
VisualC++(简称VC)是Microsoft公司推出的目前使用极为广泛的基于Windows平台的C++可视化开发环境。
VC基于C,C++语言,主要由是MFC组成,是与系统联系非常紧密的编程工具,它兼有高级,和低级语言的双重性,功能强大,灵活,执行效率高,几乎可说VC在 Windows平台无所不能。
VC主要是针对Windows系统,适合一些系统级的开发,可以方便实现一些底层 的调用。
在VC里边嵌入汇编语言很简单。
当对系统性能要求很高的时候,可用VC开发。
VC在多线程、网络通信、分布应用方面,有着不可比拟的优势。
1.3可行性分析
本课程设计主要解决在客户端于客户端的信息交换和客户端于服务器的信息交换及服务器的信息处理上的管理的课程设计。
此程序主要分为两部分:
服务器端和客户端。
服务器端用于提供一个网络端口,等待客户端发出请求,登录到此服务端,然后进行网络通讯和消息的转发;客户端可通过服务器端的IP地址发送连接请求,然后登陆聊天室。
在服务器端的成员列表栏中会显示在线的所有人名单,有人退出聊天室,成员列表会自动除名。
服务器端同时也提供了成员之间的私聊功能,此时服务器端作为一个转发站,进行消息的转发。
整个程序的主体使用了CSocket类的方法,实现了网络通讯聊天。
先启动服务器端聊天程序,这是聊天服务器需要指定一个端口号,客户端则根据这个端口号以及服务器的网络地址与服务器进行通信。
在这里,把端口号成为“聊天频道”。
在后面的程序代码分析中将看到,端口号并不等同于聊天频道,而是在聊天频道上增加一个固定的偏移值,使得这个聊天频道不会和系统保留的端口发生冲突。
服务器启动后将在这个指定的端口号中等待客户的连接。
对于公共聊天室,服务器对客户的数目不做任何限制。
而对于私人聊天室,每个聊天频道则只能允许两个客户互相连接,使得一方发送的信息只能到达对方的主机中。
这里的服务器提供的是公共聊天服务。
通过分析发现,该程序完全可以通过VisualC++中MFC完成。
2需求分析
2.1设计目的
综合运用本课程及计算机网络的相关知识设计并实现一个网络应用程序,以VisualC++作为开发平台,通过实践复习巩固课堂所学的理论知识,提高对所学知识的综合应用能力。
2.2设计要求
采用客户/服务器模式,分为客户端程序和服务器端程序。
服务器采用WINSOCKI/O模型中的任一种,支持多个客户同时在线聊天。
客户端程序和服务器程序通过网络交换聊天字符串内容,服务器窗口的列表框中显示当前在线用户,支持客户端之间的私聊(可以通过服务器中转,或考虑UDP打洞直接建立端端连接)。
课程设计要求设计并编程完成两个方面的内容:
首先建立一个使用TCP协议的聊天室服务器,这个服务器可以同时支持多个用户的在线聊天;其次设计一个可以和服务器通信的聊天室客户端。
2.3功能要求
✧支持多个客户端的连接,在服务器和多个客户端之间进行数据传输;
✧接收客户端发送的消息,并显示在一个列表框中;
✧在用户连接上后有提示,显示出连接的用户名字;
✧发送信息时可以显示聊天的所有记录;
2.4系统主要功能和主要功能描述
服务器端聊天程序必须能够做3件事情:
(1)服务器聊天程序要在待定的端口上等待来自聊天客户的连接请求,并且需要维护一个客户连接表,以记录所有成功的连接。
(2)服务器聊天程序要及时接受从各个聊天客户发送过来的信息,然后把这些信息转发到一个或多个客户连接。
对于公共聊天室,服务器将把接受到的信息向除源端外的所有客户发送过去。
(3)服务器还要监控这些连接的状态,在客户主动离开或发生故障时从列表中删除相应的表项,并及时更新连接表。
客户端聊天程序需要完成以下几个功能:
(1)客户端聊天程序要负责建立和维护与服务器的连接,通过获取用户的设置尝试与服务器的连接,并且随时检测连接的状态。
(2)客户端聊天程序要把用户输入的信息及时发送到聊天服务器。
一般情况下,当用户输入一行信息并且按下回车键后聊天程序就要把这一行信息发送出去,才能及时地满足用户的交互需求。
(3)要随时准备好接受来自服务器的信息,随时把接受到的信息显示出来,让用户及时看到对方的响应。
(4)在用户退出聊天过程是要关闭与服务器的连接。
比较好的做法是提前通知服务器或者直接给服务器发送一条退出通知,使得服务器能够及时掌握客户端的连接状态,把对方客户的退出信息及时发送到对等实体上。
3设计流程图
根据对用户的要求及功能设置可以得到以下的流程图3.1,用户首先启动客户端,登陆服务器并向服务器发送信息,启动服务器,服务器等待客户要求并向客户反馈在线用户信息,用户向服务器发送信息,服务器处理用户的数据,然后用户开始聊天。
客户端的聊天分为对所有人的信息和私聊的信息,该信息应通过程序控制分别进行处理。
图3.1设计流程图
4程序的实现
4.1项目创建
本例将使用VisualC++6.0创建一个基于对话框的MFCAppWizard(exe)项目
取名为“Chat”。
在MFC向导的第一步界面中选择“Dialogbased”单选按钮,在MFCAppWizard向导的第二步界面中选择“WindowsSockets”复选框,其它均采用默认设置。
4.2界面设计
打开IDD_CHAT_DIALOG对话框,该对话框将是程序运行时的主界面,以下是为对话框添加的控件。
如下所示:
IDD_CHAT_DIALOG对话框中的主要控件
ID
属性设置
分组框
IDC_STATIC
标题“”
静态文本
IDC_STATIC
标题“IP地址”
IP地址控件
IDC_SERVERIP
默认
静态文本
IDC_STATIC
标题“端口”
编辑框
IDC_PORT
默认
分组框
IDC_STATIC
标题“聊天记录”
编辑框
IDC_SHOWTEXT
样式:
多行,只读
静态文本
IDC_STATIC
标题“昵称”
编辑框
IDC_NAME
默认
命令按钮
IDC_CONNECT
标题“连接服务器”
命令按钮
IDC_SETSERVER
标题“建立服务器”
静态文本框
IDC_STATIC
标题“消息”
编辑框
IDC_INPUTTEXT
默认
命令按钮
IDC_SEND
标题"发送”
完成控件添加后的对话框如下图所示:
添加完上述控件后,打开Classwizard,为IDD_CHAT_DIALOG指向的CChatRoomDig类按照如下表添加成员变量。
成员变量的添加
控件ID
变量名
数据类型
IDC_PORT
m_uport
UNIT
IDC_SHOWTEXT
m_sShowString
CString
IDC_NAME
m_sName
CString
IDC_INPUTTEXT
m_sInputText
CString
4.3代码编写
聊天程序一共有6个类,其中CChatApp由AppWiardS实现;CServerSocket和CClientSocket分别负责服务端和客户端的网络通信功能;CChatDig为程序的主控类,主界面、通信方式及程序逻辑均由该类实现,它继承自CDialog类;CMessage是对消息的封装。
CAboutDig由AppWizard实现。
(1)CClientSocket类
本类通过相应的OnReceive消息来接受数据,相应OnClose消息来断开对话的处理。
CClientSocket类实现了以CArchive对数据进行的串行化。
事实上大多利用CSocket来传输数据的应用程序都会考虑到串行化的问题,因为这样可以给数据的传送带来方便。
类定义代码如下:
#include"PackMessg.h"
/////////////////////////////////////////////////////////////////////////////
//CClientSocketcommandtarget
classCChatDlg;
classCClientSocket:
publicCSocket
{
//Attributes
public:
CArchive*m_aSessionIn;
CArchive*m_aSessionOut;
CSocketFile*m_sfSocketFile;
CChatDlg*m_dlg;
boolm_bInit;//作为套接字是否被初始化的标记
boolm_bClose;//作为套接字是否被关闭的标记
//Operations
public:
voidInit(CChatDlg*dlg);
BOOLSendMessage(CPackMessg*msg);
voidCloseSocket();
public:
staticintGetLocalHostName(CString&sHostName);//获得本地计算机名称
staticintGetIpAddress(constCString&sHostName,CString&sIpAddress);//获得本地IP
staticintGetIpAddress(constCString&sHostName,BYTE&f0,BYTE&f1,BYTE&f2,BYTE&f3);//获得本地IP
staticCStringErrorReason(inttag);
public:
CClientSocket();
virtual~CClientSocket();
在CClientSocket.cpp文件中添加的代码如下:
#include"stdafx.h"
#include"chatzyj.h"
#include"ClientSocket.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
//CClientSocket
CClientSocket:
:
CClientSocket()
{
m_aSessionIn=NULL;
m_aSessionOut=NULL;
m_sfSocketFile=NULL;
m_bInit=false;
m_bClose=false;
}
CClientSocket:
:
~CClientSocket()
{
if(m_aSessionIn)
deletem_aSessionIn;
if(m_aSessionOut)
deletem_aSessionOut;
if(m_sfSocketFile)
deletem_sfSocketFile;
}
//Donoteditthefollowinglines,whichareneededbyClassWizard.
#if0
BEGIN_MESSAGE_MAP(CClientSocket,CSocket)
//{{AFX_MSG_MAP(CClientSocket)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif//0
/////////////////////////////////////////////////////////////////////////////
//CClientSocketmemberfunctions
voidCClientSocket:
:
OnReceive(intnErrorCode)
{
//TODO:
Addyourspecializedcodehereand/orcallthebaseclass
CSocket:
:
OnReceive(nErrorCode);
do{
CPackMessgtemp;
temp.Serialize(*m_aSessionIn);
m_dlg->m_sMsgList+=temp.m_strText+"\r\n";
m_dlg->SetDlgItemText(IDC_SHOWMESSAGE,m_dlg->m_sMsgList);
intlinenum=((CEdit*)(m_dlg->GetDlgItem(IDC_SHOWMESSAGE)))->GetLineCount();
((CEdit*)(m_dlg->GetDlgItem(IDC_SHOWMESSAGE)))->LineScroll(linenum);
if(!
m_dlg->m_bClient)
{
for(POSITIONpos=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());
}
voidCClientSocket:
:
OnClose(intnErrorCode)
{
//TODO:
Addyourspecializedcodehereand/orcallthebaseclass
CSocket:
:
OnClose(nErrorCode);
m_bClose=true;
CloseSocket();
m_dlg->CloseSessionSocket();
CSocket:
:
OnClose(nErrorCode);
}
voidCClientSocket:
:
Init(CChatDlg*dlg)
{
m_sfSocketFile=newCSocketFile(this);
m_aSessionIn=newCArchive(m_sfSocketFile,CArchive:
:
load);
m_aSessionOut=newCArchive(m_sfSocketFile,CArchive:
:
store);
m_bClose=false;
this->m_dlg=dlg;
}
BOOLCClientSocket:
:
SendMessage(CPackMessg*msg)
{
if(m_aSessionOut!
=NULL)
{
msg->Serialize(*m_aSessionOut);
m_aSessionOut->Flush();
returnTRUE;
}
else
{
//对方关闭了连接
m_bClose=true;
CloseSocket();
m_dlg->CloseSessionSocket();
returnFALSE;
}
}
voidCClientSocket:
:
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;
}
intCClientSocket:
:
GetLocalHostName(CString&sHostName)//获得本地计算机名称
{
charszHostName[256];
intnRetCode;
nRetCode=gethostname(szHostName,sizeof(szHostName));
if(nRetCode!
=0)
{
//产生错误
sHostName=_T("没有取得");
returnGetLastError();
}
sHostName=szHostName;
return0;
}
intCClientSocket:
:
GetIpAddress(constCString&sHostName,CString&sIpAddress)//获得本地IP
{
structhostentFAR*lpHostEnt=gethostbyname(sHostName);
if(lpHostEnt==NULL)
{
//产生错误
sIpAddress=_T("");
returnGetLastError();
}
//获取IP
LPSTRlpAddr=lpHostEnt->h_addr_list[0];
if(lpAddr)
{
structin_addrinAddr;
memmove(&inAddr,lpAddr,4);
//转换为标准格式
sIpAddress=inet_ntoa(inAddr);
if(sIpAddress.IsEmpty())
sIpAddress=_T("没有取得");
}
return0;
}
intCClientSocket:
:
GetIpAddress(constCString&sHostName,BYTE&f0,BYTE&f1,BYTE&f2,BYTE&f3)//获得本地IP
{
structhostentFAR*lpHostEnt=gethostbyname(sHostName);
if(lpHostEnt==NULL)
{
//产生错误
f0=f1=f2=f3=0;
returnGetLastError();
}
//获取IP
LPSTRlpAddr=lpHostEnt->h_addr_list[0];
if(lpAddr)
{
structin_addrinAddr;
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;
}
CStringCClientSocket:
:
ErrorReason(inttag)
{
CStringresult;
switch(tag)
{
caseWSANOTINITIALISED:
result="AsuccessfulAfxSocketInitmustoccurbeforeusingthisAPI.";
break;
caseWSAENETDOWN:
result="thenetworksubsystemfailed";
break;
caseWSAEADDRINUSE:
result="Thespecifiedaddressisalreadyinuse";
break;
caseWSAEINPROGRESS:
result="AblockingWindowsSocketscallisinprogress";
break;
caseWSAEADDRNOTAVAIL:
result="Thespecifiedaddressisnotavailablefromthelocalmachine";
break;
caseWSAEAFNOSUPPORT:
result="Addressesinthespecifiedfamilycannotbeusedwiththissocket";
break;
caseWSAECONNREFUSED:
result="Theattempttoconnectwasrejected";
break;
caseWSAEDESTADDRREQ:
result="Adestinationaddressisrequired";
break;
caseWSAEFAULT:
result="ThenSockAddrLenargumentisincorrect";
break;
caseWSAEINVAL:
result="Invalidhostaddress";
break;
caseWSAEISCONN:
result="Thesocketisalreadyconnected.";
break;
caseWSAEMFILE:
result="Nomorefiledescriptorsar
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 山东 建筑 大学 课程设计