面向对象编程技术作业题Word文档下载推荐.docx
- 文档编号:22936064
- 上传时间:2023-02-06
- 格式:DOCX
- 页数:29
- 大小:468.30KB
面向对象编程技术作业题Word文档下载推荐.docx
《面向对象编程技术作业题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《面向对象编程技术作业题Word文档下载推荐.docx(29页珍藏版)》请在冰豆网上搜索。
实现通信过程的具体算法流程参考了VC++深入详解,基本按照如下步骤建立的。
1.加载套接字库,调用WSAStartup函数初始化。
2.创建并初始化套接字,为定义的ChatDlg类增加SOCKET变量,实现初始化,自定义套接字相关消息
3.实现接收端功能。
4.实现发送端功能。
5.终止套接字库使用。
6.利用主机名实现网络访问。
动态显示用户算法实现,以服务端为例,首先创建一个结构体变量,存储于
用户相关的信息。
当然这个结构体数组的大小决定服务器支持连接用户的大小。
当一个用户发来连接请求时,将此用户的信息添加到结构体数组中,如果有用户发来断开请求时,接收消息成功后,将用户从此数组中删除。
没有一次这样的操作,都选择对显示此项功能的List进行更新。
私聊功能算法实现,假设甲乙两个用户,甲要对乙私聊,甲向服务器发送消息时,应当携带私聊的内容那个消息和私聊的对象的消息,然后服务器获得此消息后,直接将消息转发给乙,而不向任何连接的用户发送消息。
同样,屏蔽消息功能的算法相同,只是在自己客户端接收的消息中,找到发给自己的消息显示并记录(实际上已经接收到服务器发给本端的所有消息,只不过不予显示)。
传输文件算法也是相同,找到要传输端,然后向客户端发送相应的消息,客户端判定是什么网络事件,在case中作处理,发送给要传送的客户端,将这两端联系起来,实现了点到点的连接,可以收发文件了。
将聊天信息保存的实现,我采取了首先写一个全局的函数,函数完成功能是新建一个以“聊天记录”或“客户端名字”的.txt文件。
然后再程序中,每一个收发消息的判断后将这段函数加上,将传递的信息内容取出,追加到建立的文件的尾端,写入后关闭。
三、方案设计
本算法基于VisualC++6.0编程,采用MFCAppWizard(exe)工程,基于对话框(添加控件十分简单,所以放弃用VIEW视图)实现的聊天系统。
分服务端和客户端。
(一)服务器端
在算法设计中已经提到,本程序是根据基于消息的异步套接字实现,再此不
再赘述具体的建立的过程。
本节细致的介绍一下服务器的设计并实现的具体方案
主窗口:
主窗口的主要控件有static型的,显示服务器名,服务器所在的IP地址。
还有Editbox,主要显示系统及用户之间聊天交互的信息。
另外还有三个按钮,对应三个消息函数,具体的功能在按钮上有体现。
最后还有一个static的空间,可以动态显示人数,就是将此对话框类的成员变量的数目显示出来。
具体在编程实现中给出。
显示在线用户窗口:
通过相应点击在主窗口按钮的消息对应函数,启动了显示在线用户的窗口,起初是用来清除用户的,后来经改进,将主控件LISTBOX改成了TREE后,用来显示在线的连接用户。
除此之外,还可以看到两个按钮控件,第一个按钮相应的是阻止用户连接的消息,第二个是退出功能,更名为返回服务器。
当选择列表中的某一用户时,点击阻止用户连接功能,可以实现将用户与服务器连接断开。
如下图表示。
当选择是,用户王宇将被踢出服务器,同时在主窗口对整个数据更新。
(二)客户端
客户端分为登录界面和聊天的主界面。
其中登录界面应用了Microsoft提出
的应用程序接口(API)用以实现访问关系或非关系数据库中的数据ADO。
ADO类的设计和编写有现成的程序作参考,建立的db.db文件主要保存用户登录的信息和IP地址。
其中在登录界面的对话框类中引用为默认的值。
对话框界面如下图示:
下面对其中的主要控件介绍,两个能编辑的控件,IPADDRESS和EDIT可以输入用户要连接的服务器信息和用户的昵称。
其中默认的从以保存的db.db文件中读取,也可以修改,并保存到db.db数据库文件中,若不希望用ado类,可修改代码将之删除。
另外还有两个按钮控件,当点击确定按钮时,将服务器IP和用户昵称两个信息传递的对应的变量中,启动主窗口。
点击取消按钮退出。
底部空白处,隐藏控件如下图:
下面对主界面的主要控件及功能的具体设计做以简明的概要。
右侧的listbox用以显示连接后用户的当前与服务器连接的动态信息。
左侧上面的Editbox可以显示系统消息和聊天消息。
下面的Editbox用以书写发送消息的内容。
位于两个Editbox中间的下拉菜单列表框用来选择发送消息的对象,后面两个checkbox用来原则是否私聊,和对消息进行过滤。
后面的那个带文件夹图标的按钮,处理传送文件的消息函数,用对某一对象发送文件。
下面隐藏的控件有进度条。
接收,和取消按钮,用于对文件传输的操作,分别对应显示传送文的进度,是否接收和取消。
其中传输速度用一个很简单的算法就可以计算出来。
也没有必要再算法概要中说明。
具体的说明见编程实现。
四、编程实现
本节介绍聊天室的服务端和客户端的编程实现,主要通过对实现聊天室功能的类分别来进行表述。
(1)服务器端
(I)CServerDlg类
定义了成员变量有两个结构体变量structsendinfo用于存储发送消息的内容包括发送消息的成员名和消息内容,消息内容长度在400以内。
另外userinfo结构体中用于存储连接者的用户名和ip信息。
同时定义了CString类的成员变量,用以代表当前连接的用户数。
下面主要介绍一下服务器进行通信的流程。
初始化套接字
boolCServerDlg:
:
InitSocket()
{
WSADATAwsaData;
//初始化TCP协议
BOOLret=WSAStartup(MAKEWORD(2,2),&
wsaData);
if(ret!
=0)
{
MessageBox("
InitialTCPProtocolFailed!
"
);
returnfalse;
}
for(inti=0;
i<
MAX1;
i++)
{
SocketAccept[i]=INVALID_SOCKET;
}
ListeningSocket=socket(AF_INET,SOCK_STREAM,0);
if(ListeningSocket==INVALID_SOCKET)
CreateSOCKETFailed"
WSACleanup();
closesocket(ListeningSocket);
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.s_addr=0;
serveraddr.sin_port=htons(2010);
WSAAsyncSelect(ListeningSocket,m_hWnd,WM_SERVER_ACCEPT,FD_ACCEPT|FD_READ|FD_CLOSE);
/*设置为异步通讯模式,并为它注册各种网络异步事件,
其中m_hWnd为应用程序的主对话框或主窗口的句柄
当检测到相应时间后才为窗口句柄发送消息*/
if(bind(ListeningSocket,(sockaddr*)&
serveraddr,sizeof(serveraddr))==SOCKET_ERROR)
BindFailed"
if(listen(ListeningSocket,20)==SOCKET_ERROR)
ListenFailed"
HostInfo();
m_strMsg="
服务器初始化成功!
\r\n等待用户连接......."
;
UpdateData(false);
returntrue;
}
等待客户请求,处理对应的网络事件
服务器端有接收到消息时,响应的消息处理函数,异步套接字的好处是不用在客户端设置死循环了,标记发送消息的事件即可处理。
这是本程序的重点。
先把程序代码罗列如下。
LRESULTCServerDlg:
OnServerAccept(WPARAMwParam,LPARAMlParam)
//wParam参数标识了网络事件发生的套接口.lParam的低字指明了发生的网络事件.
intiEvent=WSAGETSELECTEVENT(lParam);
switch(iEvent)
caseFD_ACCEPT:
//客户端连接请求事件
OnAccept(wParam,lParam);
break;
caseFD_CLOSE:
//客户端断开事件:
OnClose(wParam,lParam);
caseFD_READ:
//网络数据到达事件
OnReceive(wParam,lParam);
default:
break;
return0;
可以看出异步套接字是针对网络事件的,所以本函数要获得是哪个套接口发来的什么样的网络事件。
从switchcase语句中能看出此函数处理了三个消息网络事件,分别是客户连接,客户断开和连接后有数据需要读取。
于是又有了3个新的函数,分别针对每一个网络事件完成相应功能。
处理连接请求的子函数:
voidCServerDlg:
OnAccept(WPARAMwParam,LPARAMlParam)
inti,addrlen;
for(i=0;
MAX1&
&
SocketAccept[i]!
=INVALID_SOCKET;
i++){}
if(i==MAX1)
return;
sockaddr_inclientsocket;
addrlen=sizeof(clientsocket);
SocketAccept[i]=accept(ListeningSocket,(sockaddr*)&
clientsocket,&
addrlen);
if(i==MAX)
sendinfoerr;
err.type=4;
CStringm;
m="
服务器已达到最大连接数"
memcpy(err.msg,m,m.GetLength()+1);
send(SocketAccept[i],(char*)&
err,sizeof(err),0);
Sleep(500);
closesocket(SocketAccept[i]);
return;
uinfo[i].userip=inet_ntoa(clientsocket.sin_addr);
//32位ip转字符型ip;
people.Format("
%d"
atoi(people)+1);
GetDlgItem(IDC_STATIC2)->
SetWindowText(people);
此函数接收两个变量,wParam对应的套接口,低字节的对应相应的事件。
当连接的套接字有效的时候,并且连接的用户数在指定用户数目范围内相应accep函数;
accept函数从处于监听状态,并且接收连接用户的IP地址和端口信息。
当定义的用户数超过最大值时,将向此用户发送信息,表明系统不能容纳他,并将分配给他的套接口关闭。
客户端断开的处理函数:
OnClose(WPARAMwParam,LPARAMlParam)
inti;
=wParam;
if(i==MAX1)return;
sendinfoinfo;
info.type=3;
//peopleexit
CTimet=CTime:
GetCurrentTime();
CStringstrTime="
[%y-%m-%d%H:
%M:
%S]"
s;
strTime=t.Format(strTime);
s=uinfo[i].username;
memcpy(info.name,s,s.GetLength()+1);
CStringm,mtemp;
m=strTime+"
系统消息:
\r\n用户"
+uinfo[i].username+"
退出聊天室"
m_strMsg=m_strMsg+"
\r\n"
+strTime+"
用户"
(IP:
+uinfo[i].userip+"
)退出服务器"
mtemp=strTime+"
UpdateData(FALSE);
MSG_Write(mtemp,"
聊天记录"
atoi(people)-1);
CEdit*edit=newCEdit;
edit=(CEdit*)GetDlgItem(IDC_EDIT4);
edit->
LineScroll(edit->
GetLineCount(),0);
memcpy(info.msg,m,m.GetLength()+1);
for(intj=0;
j<
MAX&
SocketAccept[j]!
j++)
if(i!
=j)
send(SocketAccept[j],(char*)&
info,sizeof(info),0);
uinfo[i].userip="
uinfo[i].username="
closesocket(SocketAccept[i]);
SocketAccept[i]=INVALID_SOCKET;
接收消息,向套接口不是该用户的其他用户发送此用户断开的消息,对接收到的消息转换为CString型的,经过处理,比如说加上CTime类中获得的当前时间信息后,合并为一个字符串,通过send()函数向所有在线用户广播。
最后将分配给当前选择退出的用户的套接口关闭。
接收发送消息函数,此函数比较复杂,主要完成对发送数据报事件的处理,其中不然调用recv()函数,并对recv接收的消息缓冲区中接收信息的类型做判断,info,是上文所说的结构体,保存消息内容和消息类型。
消息类型为1,是对所有用户,将信息发到所有的用户,用send()函数,不在赘述。
0是增加新用户,如果用户昵称存在,向这一套接口的用户发送重名消息,否则,将其连入网内,并向所有端口的人发送消息。
同时进行更新LISTBOX中在线人数的逻辑。
5是发送文件,7是私聊。
清除用户函数
OnButtonClear()
//TODO:
Addyourcontrolnotificationhandlercodehere
CClearDlgdlg;
dlg.dlg=this;
if(dlg.DoModal()==IDOK)
{inti=0;
for(i=0;
uinfo[i].username!
=dlg.name;
{
}
sendinfoinfo;
info.type=3;
CTimet=CTime:
CStringstrTime="
strTime=t.Format(strTime);
s=uinfo[i].username;
memcpy(info.name,s,s.GetLength()+1);
CStringm,mtemp;
m=strTime+"
被踢出聊天室"
m_strMsg=m_strMsg+"
)被管理员踢出出服务器"
mtemp=strTime+"
UpdateData(FALSE);
CEdit*edit=newCEdit;
edit=(CEdit*)GetDlgItem(IDC_EDIT4);
edit->
MSG_Write(mtemp,"
memcpy(info.msg,m,m.GetLength()+1);
for(intj=0;
uinfo[i].userip="
uinfo[i].username="
if(atoi(people)>
0)////消除同时推出时的BUG用户为-1现象
people.Format("
GetDlgItem(IDC_STATIC2)->
选择某一用户,给所有人发送要清除他的信息,然后将对应清除者的套接口关闭。
同时将在线用户更新。
(II)ClearDlg类
主要对此对话框的控件相应函数操作。
对树形表的控件,有初始化操作,和增加新的用户信息操作,程序代码如下。
BOOLCClearDlg:
OnInitDialog()
CDialog:
OnInitDialog();
Addextrainitializationhere
m_ctrList.InsertColumn(0,"
用户名"
//树形表第一栏标题
m_ctrList.SetColumnWidth(0,80);
m_ctrList.InsertColumn(1,"
用户IP"
//树形表第二栏标题
m_ctrList.SetColumnWidth(1,125);
m_ctrList.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
RefreshData();
returnTRUE;
//EXCEPTION:
OCXPropertyPagesshouldreturnFALSE
voidCClearDlg:
RefreshData()
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 面向 对象 编程 技术 作业题