《VC++高级程序设计大作业基于局域网的聊天室设计与开发.doc》由会员分享,可在线阅读,更多相关《VC++高级程序设计大作业基于局域网的聊天室设计与开发.doc(21页珍藏版)》请在三一办公上搜索。
1、基于局域网的聊天室设计与开发摘要 系统是在在VC+6.0开发环境下使用基于对话框架构和网络编程技术实现了一个基于局域网的聊天室。系统分为客户端程序和服务器端程序,两者分开运行。服务器提供主机IP地址和端口供众多的客户端连接。既可以一对一聊天,也可以一对多聊天。关键字:聊天室;局域网;基于对话框;Socket通信目录1.开发环境介绍11.1 Visual C+6.0集成开发环境使用方法介绍11.2WinSock技术51.2.1WinSock概述51.2.2CSocket类编程模型62.基于局域网的聊天室设计72.1系统总体目标72.2系统功能模块图73.基于局域网的聊天室实现83.1 服务器开启
2、与客户连接以及局域网通信83.2系统各个模块的实现103.2.1服务器103.2.2客户端154.系统测试185. 总结19参考文献191.开发环境介绍1.1 Visual C+6.0集成开发环境使用方法介绍本系统涉及的C+语言源程序,均在Visual C+ 6.0(后简称VC6)开发环境中进行编制和调试。这里将简要介绍VC6集成开发环境的使用和调试方法。1VC6的用户界面介绍双击安装好的VC6图标后,可以看到附图1.1所示的界面,此时VC6处于编辑状态。图1.1 VC+ 6.0编辑状态的用户界面其中菜单栏集成了VC6的各种命令、功能和设置;工具栏则将最常用的命令、功能和设置直接用图标的形式给
3、出,方便用户使用;“Workspace”子窗口(工作空间子窗口)可以把VC6工程中使用的各种类和文件按树形结构来浏览;文件子窗口则用来具体显示和编辑VC6工程所用到的文件,比如C+源文件、头文件等;输出子窗口用来显示编译、连接或者搜索等操作的结果。2VC 6集成开发环境的使用简介(1)创建VC6工程要使用VC6来编译一个C或者C+源文件,必须把这个文件插入一个VC6工程中,因此,先介绍VC6工程的创建步骤: 点击“File”菜单,选择“New”菜单项,弹出“New”窗口; 切换“New”窗口选项卡为“Projects”,选择“Win32 Console Application”(Win32控制
4、台应用程序),本书只使用这类工程即可; 在“Location:”下的文本框内填入工程保存的文件夹位置,也可以点其右侧的“”按钮来定位文件夹; 在“Project name:”下的文本框内填入工程的名称,例如Prj1。其它设置不用更改; 点“OK”后,出现“Win32 Console Application”设置向导窗口,选“An empty project”,点“Finish”,再点“OK”后,工程创建结束。这时,一个空的Win32 Console Application工程就创建好了。此时,“Workspace”子窗口就会显出“ClassView”(类浏览)和“FileView”(文件浏览)
5、两个选项卡。本书不使用类来编程,因此不介绍“ClassView” 选项卡。切换到“FileView”选项卡,可以看到树形的列表中,将工程所有的文件分为三大类,即“Source Files”(源文件)、“Head Files”(头文件)和“Resource Files”(资源文件)。本书程序不涉及自编头文件和资源文件,因此不必向这两类添加文件。而“Resource Files”下现在没有任何文件,需新建或者利用已有的源文件插入工程中,才能进行编译。(2)新建C或C+源文件并插入工程的方法 点击“File”菜单,选择菜单项“New”,弹出“New”窗口; 选择“New”窗口“Files”选项卡,选
6、择“C+ Source File”; 在“File”下的文本框内填入带后缀的源文件名,后缀为.c或是.cpp,分别代表C源文件和C+源文件,例如填入main.c; 保证“Add to project”前的复选框被选中,且其下的下拉列表框所选的工程为刚刚创建的空工程的名字; 点“OK”后,一个空的源文件main.cpp就被插入工程Prj1了。此时,文件子窗口会打开新建的源文件,以备编辑。至此,源文件的创建结束。(3)将原有的C或C+源文件插入工程的方法 右击“Workspace”子窗口“FileView”选项卡中的“Source Files”文件夹,选择“Add Files to Folder”
7、快捷菜单项; 选择需要插入工程的全部源文件,点“打开”,这时全部源文件就被插入工程中了。展开“Source Files”文件夹,可以看到其下有刚刚插入的全部源文件。双击其中一个,文件子窗口就会打开对应的源文件,并使之最前显示,进入编辑状态。同时,VC6标题栏内的中括号中会出现该文件的名字。(4)保存工程中被编辑过的一个或多个文件将新建或者已有的源文件插入工程中后,就可以在文件子窗口中对源文件中的程序代码进行编辑。编辑后,可以点击“Stantard”工具栏的两个按钮进行保存。其中,第一个按钮只是保存当前文件子窗口中最前端显示的被编辑文件,其对应的快捷键是Ctrl+S;第二个按钮则可保存全部源文件
8、。(5)编译、连接和调试VC6的工程编译和连接编译和连接对应的菜单为“Build”菜单,其中常用以下三个菜单项:“Compile”菜单项,只编译当前处于编辑状态的源文件;“Build 工程名.exe”菜单项,是在全部源文件编译之后,连接并生成可执行文件;“Rebuild All”项一般用在对源文件更改后,重新编译连接。如果发现任何的编译和连接错误或警告,VC6会在输出子窗口中给出提示。双击该提示,会转到源程序的出错行。可以搜索VC6的帮助以获取更多有关编译、连接错误的信息,以便排除这些错误和警告。错误及警告更正后,应用“Rebuild All”重新进行编辑和连接。 运行程序如需运行连接好的程序
9、,可选“Build”菜单下的“Execute 工程名.exe”菜单项。调试方法要进入调试状态,可以选择“Build”菜单下“Start Debug”子菜单中的菜单项。其中常用的是前三项:“Go”、“Step into”和“Run to Cursor”菜单项,它们的含义参见后述。VC6从编辑状态进入调试状态后,用户界面会有所变化。如图1.2所示,原“Workspace”子窗口会消失,“Build”菜单会变为“Debug”菜单,原输出子窗口会变成图1.2 VC+ 6.0调试状态的用户界面“Variables” 子窗口(变量子窗口)和“Watch” 子窗口(监视子窗口)。同时,在调试状态下,VC6会
10、打开“Debug”工具栏。这个工具栏各按钮的功能与“Debug”菜单中的各菜单项对应。下面将常用的“Debug”菜单项分别说明如下:a“Go”菜单项:按流程顺序批量运行程序语句,遇到断点(Breakpoint)时调试暂停;b“Restart”菜单项:重新开始调试;c“Stop Debugging”菜单项:停止调试,VC6返回编辑状态;d“Step into”菜单项:逐句执行源程序,并且如果遇到子程序会进入子程序内执行;e“Step over”菜单项:逐句执行源程序,但不会进入子程序中;f“Step out”菜单项:从当前的子程序中跳出,返回调用它的上一级程序;g“Run to Cursor”菜
11、单项:执行到文件子窗口中,当前被编辑源文件的光标所在行处。要使用“Go”菜单项,应在源文件的可执行语句前添加断点。有关断点的具体操作如下: 在文件子窗口中,打开想进行断点操作的行所在的源文件,并把光标移至该行; 右击该行,在快捷菜单中选择“Insert/Remove Breakpoint”(添加/删除断点)菜单项。如果该行之前未设过断点,这一行前就会出现一个棕色的实心圆点,表示该行被添加了断点;如果已设过的断点,则断点会被删除。 右击设置过断点的行,在快捷菜单中选择“Disable/Enable Breakpoint”(禁用/启用断点)菜单项,可以禁用或启用(都不会删除)断点。被禁用的断点显示
12、为棕色空心圆点,它们不会使调试暂停。最后,说明一下“Variables”子窗口和“Watch” 子窗口,它们在调试状态下非常有用。程序调试运行时,“Variables” 子窗口会自动选择的一些变量,并将它们的实时值用表格的形式显示在“Auto”选项卡中。“Watch”子窗口则可用来监视程序员指定的变量或者表达式的值,方法是将想要监视的变量或者表达式写在“Name”列下的各行中,回车后,就可看到它们的实时值。这两个窗口还可用来临时修正调试运行中的变量值,方法是在想要修改的变量后的“Value”单元格中,输入修改值,并回车,这时变量就被赋予了程序员临时给的值,而不再是程序原运行过程中被赋的值1。1
13、.2WinSock技术1.2.1WinSock概述Windows Sock(Windows套接字,简称WinSock)是微软根据UNIX操作系统中流行的Berkeley(伯克利)套接字规范,而实现的一套Microsoft Windows下的网络编程接口。微软的MFC把复杂的WinSock API函数封装到类里,这样大大减轻了程序员的负担,程序不需要明白底层通信具体的实现机制,使得编写网络应用程序更加快速、更加容易。主要有两个类:CAsyncSocket类和CSocket类。首先CAsyncSocket类几乎逐个封装了WinSock API,这个类是以程序员了解网络通讯为前提,程序员使用这个类的
14、时候,可以在MFC中使用WinSock,并且肩负着处理诸如阻塞、字节顺序和在Unicode与MBCS 间转换字符的责任,虽然给编程带来了一定的技术难度和较多的代码量,但是它为高级网络程序员提供了更加有力而灵活的方法。考虑到CAsyncSocket类在编程时,程序员考虑的问题还是比较多,MFC给出了CSocket类,这个类继承于CAsyncSocket类,它提供了比CAsyncSocket更高层的WinSock API接口。相比起来,CSocket类代表了一个比CAsyncSocket对象更高层次的Windows Socket的抽象,CSocket类与CSocketFile类和CArchive类
15、一起工作来发送和接收数据,除此之外CSocket类和CSocketFile类可以与Carchive类一起合作来管理发送和接收的数据,这使管理数据收发更加便利,因此使用CSocket类编写网络应用程序更加方便。但是它牺牲掉了CAsyncSocket类的灵活性。同时CSocket对象提供阻塞模式,所谓阻塞是指直到操作完成后才返回控制权,在完成操作返回之前进程被挂起,什么也不能做。常见的阻塞函数有Receive()、Send()、ReceiveFrom()、SendTo() 和Accept()。假如一个socket处于非阻塞模式(即异步操作),则会被调用函数立即返回,通信效率较高。对于CAsyncS
16、ocket类可以用GetLastError 成员函数查询最后的错误,如果错误返回值为WSAEWOULDBLOCK,则说明有阻塞,而CSocket绝不会返回WSAEWOULDBLOCK,因为它在自己类的内部已经实现了阻塞管理,减轻了程序员负担,但是却牺牲了通信的高效性。是不是使用CSocket类就不能实现类似CAsyncSocket类的高效非阻塞操作呢?也不是,使用使用多线程的方法既可以使程序员享受CSocket带来的简化编程的便利,也不会影响用户界面对用户的反应,可谓一举两得。 综合上述各个因素以及两个类的特点可以得知,如果需要低层控制和高效率,就使用CAsyncSock类;如果需要方便,则可
17、使用CSocket类;如果既想编程方便又想高效率通信,则可以联合使用CSocket类和多线程编程4。1.2.2CSocket类编程模型当我们在使用CSocket对象编写网络通信应用程序时候,需要涉及到CArchive类和CSocketFile 类对象。以下介绍的针对字节流型套接字CSocket类编程模型的实现过程中,服务器方和客户方的实现过程几乎没有什么差异,唯一的区别仅在第2步。1使用CSocket类产生一个对象,然后调用CSocket类对象的成员函数Create()产生一个Socket句柄。这个过程对于数据报套接字,CAsyncSocket和CSocket 的使用方法没有什么区别。2在这里
18、,我们要分服务器与客户端区分对待。假如第一步创建的是客户方套接字,调用CSocket类的基类成员函数CAsyncSocket Connect()来与服务方套接字连接;反之,如果在前面我们创建的是服务方套接字,那么就要开始监听,相应的调用基类的成员函数CAsyncSocketListen()开始监听来自客户方的连接请求,当服务器方正确收到客户方的连接请求后,服务器方调用CAsyncSocketAccept()成员函数来响应接受请求,并且建立连接。同样地,Accept()成员函数的参数为一个新的并且为空的CSocket对象。3接着我们就需要构造一个CSocketFile对象,并且将它与CSocke
19、t 对象关联起来,以便供后面的通信使用。4在完成前面一些列的准备工作后,我们就要正式开始接收和发送数据了。为了完成这个工作,首先我们为接收和发送数据各构建一个CArchive 对象,与此同时将它们与上面构造的CSocketFile对象也关联起来。在这里我们需要特别注意的是,CArchive类是不能和数据报套接字一起工作,实现数据接收和发送的。5在客户与服务方使用CArchive对象的Read()、Write()等函数传送、接收数据。6当服务方和客服方结束双方的通信后,完成一系列的清理工作,具体工作是先后销毁CArchive、CSocketFile和CSocket对象6.7。2.基于局域网的聊天
20、室设计2.1系统总体目标服务器端:1 服务器端可以设置开放的端口,并且可以自动检查端口是否设置的正确;2 服务器端可以自动获取本机的IP地址和主机名称;3 服务器器可以自动监听开放的端口,看是否有客户端连接;4 聊天区的信息可以自动换行,可以使用回车键发送信息;5 服务器端可以自动获取连接客户端的基本信息;6 服务器端可以统计在线的客服端,以及相应的信息;客户端:1. 客户端用户可以自己设这要连接的主机IP地址和端口,同时客户端可以设置自己的昵称;2. 连接服务器的时候,可以自动检查端口和IP地址是否正确,如果不正确,能给出提示信息;3. 退出聊天室的时候,能提示用户相应的信息。2.2系统功能
21、模块图系统包括客服端程序和服务器端程序,服务器端包括:(1)设置IP地址和端口模块;(2)监听模块;(3)聊天模块;(4)统计在线人数模块;(5)退出模块。客户端包括:(1)连接模块;(2)聊天模块;(3)退出模块。具体功能模块示意图见图2所示。图2 系统功能模块图3.基于局域网的聊天室实现3.1 服务器开启与客户连接以及局域网通信在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户机/服务器模式(client/server),客户机/服务器模式在操作过程中采取的是主动请求的方式,即客户向服务器提出请求,服务器接收到请求后,提供相应的服务。C/S模式的具体原理如下:服务器:1服务
22、器打开一个通信通道并且通知本地主机,它愿意在某一地址和端口上接收客户方的请求;2监听打开的端口,等待客户方的请求到达该端口;3服务器接收到客户请求,处理该请求,然后发送应答信号,与此同时激活一个新的进程(或线程),用来专门处理这个客户请求。激活的新进程(或线程) 仅需要处理此客户请求,并不需要对其它请求作出响应或者应答。当服务关闭后,关闭此新进程与客户的通信链路,并且终止;4返回第二步,继续监听端口,等待另一客户的请求;5关闭服务器。客户方:1服务器方打开一个通信通道,并连接到服务器方打开的特定端口;2向服务器发送服务请求报文,等待并接收服务器方的应答;继续向服务方提出请求;3请求结束后,关闭
23、自己打开通信通道,并且终止。下面将分别从服务器端与客户端两个方面详细介绍使用CSocket类、基于TCP/IP模型实现局域网通信的过程。1服务器端程序:(1)创建一个字节流套接字,并且调用Create()函数产生Socket句柄;(2)调用成员函数Bind(),将字节流套接字绑定到一个本地地址和端口上;(3)调用成员函数Listen()函数,将套接字设为监听模式,准备接收客户请求;(4)等待客户请求到来;当请求到来后,调用成员函数Accept()接受连接请求,返回一个新的对应于此次连接的字节流套接字;(5)使用返回的套接字,调用Send()和Receive()函数和客户端进行通信;(6)返回第
24、4步,等待另一客户的连接请求;(7)关闭套接字,结束通信。2客户端程序:(1)创建一个字节流套接字,并且调用Create()函数产生Socket句柄;(2)调用Connect()函数向服务器发出连接请求;(3)使用Send()和Receive()函数和服务器端进行通信。(4)关闭套接字,结束通信1112。其客户端与服务器端编程模型及其交互过程见图3.1所示:图 3.1 客户端与服务器端编程模型及其交互过程3.2系统各个模块的实现3.2.1服务器设置IP地址和端口模块此模块主要是完成一些初始化工作,其界面示意图见图3.2所示 ,具体完成的功能如下:1. 设置服务器名称,设置端口号;2. 获得主机
25、服务器IP和主机名称;3. 并将信息显示在编辑框中。图3.2 设置IP地址以及端口实现代码如下:char name100;char *ip;PHOSTENT hostinfo;if( gethostname(name,sizeof(name) = 0 ) if(hostinfo = gethostbyname(name) != NULL)ip = inet_ntoa (*(struct in_addr *)*hostinfo- h_addr_list);else AfxMessageBox(不能得到本机Ip); else AfxMessageBox(不能得到本机名称);CString name
26、_s = name;CString ip_s = ip;SetDlgItemText(IDC_EDIT3,server);SetDlgItemText(IDC_EDIT4,1030);/SetDlgItemText(IDC_EDIT2,);SetDlgItemText(IDC_STATICip,ip);SetDlgItemText(IDC_STATICname,name);监听模块监听模块主要负责监听端口,看是否有客户端连接,其示意图见图3.3所示,具体实现细节如下:1. 获得服务器IP地址,以及端口2. 格式化IP地址以及端口字符串,判断端口号是否符合要求(1)如果符合要求创建一个字节流套接
27、字,并且调用Create()函数产生Socket句柄。如果创建成功调用成员函数Listen()函数,将套接字设为监听模式,准备接收客户请求;否则给出提示信息,端口被其他应用程序占用,关闭Socket通道。(2) 如果不符合要求,给出提示信息图3.3 监听模块其具体实现代码如下:void CTcpseverDlg:Onlisten() CString ipstr,portstr;int port;GetDlgItemText(IDC_EDIT3,ipstr);severname=ipstr;GetDlgItemText(IDC_EDIT4,portstr);portstr.TrimLeft();
28、portstr.TrimRight();port=atoi(portstr);if(port0&portEnableWindow(false);cw=GetDlgItem(IDC_EDIT4);cw-EnableWindow(false);cw=GetDlgItem(IDC_listen);cw-EnableWindow(false);cw=GetDlgItem(IDC_EDIT1);cw-SetWindowText(本服务器名称为:+severname+rn正在后台等待用户连接,监听端口:+portstr+.);elseMessageBox(绑定监听端口失败,请确认该端口没有被其它程序占用)
29、;cslisten.Close();elseMessageBox(端口输入有误,请重新输入);聊天模块聊天模块的主要功能是实现客户端和服务器之间的通信,并将两者的聊天信息显示在聊天信息框中,每次接受一条信息自动换行。聊天区示意图见图3.4所示。 图3.4 聊天区示意图 图3.5 统计在线客户端信息示意图统计在线人数模块点击刷新按钮时,自动更新在线的人数以及在线客户端的基本信息。统计信息的示意图见图3.5所示。void CTcpseverDlg:OnBUTTONrefresh() int i;CString str1;CString str;str.Format(在线人数:%d,csnum);S
30、etDlgItemText(IDC_EDIT_5,str);str.Empty();for(i=0;iLineScroll(ce_2-GetLineCount()-1);退出模块当服务器端点击退出按钮时,给出提示信息,询问服务器端是否确定退出,其示意图见图3.6所示。图3.6 服务器端退出示意图其实现代码如下:void CTcpseverDlg:OnClose() CString str=服务器即将退出;int len=str.GetLength();for(int i=1;i=csnum;i+) if(csrevi) csrevi.Send(str,len);int confirm=Mess
31、ageBox(确定退出服务器吗?,其它所有用户将失去连接,请确定,MB_YESNO|MB_ICONQUESTION);if(confirm=IDYES)str=severname+退出,与服务器连接已断开;len=str.GetLength();for( i=1;i=csnum;i+) if(csrevi) csrevi.Send(str,len);CDialog:OnClose();elseCString str=服务器取消退出;int len=str.GetLength();for(int i=1;i0&portEnableWindow(false);cw=GetDlgItem(IDC_E
32、DIT2);cw-EnableWindow(false);cw=GetDlgItem(IDC_connet);cw-EnableWindow(false);cw=GetDlgItem(IDC_EDIT5);cw-EnableWindow(false);SetDlgItemText(IDC_EDIT3,已设名字+clientname+rn连接服务器成功);CString enterinfo=clientname+进入聊天室;int len=enterinfo.GetLength();clconect.Send(enterinfo,len);Sleep(100);CString Cname4sen
33、d=#:+clientname+,+ip+,+name;clconect.Send(Cname4send,Cname4send.GetLength();elseclconect.Close();MessageBox(连接失败,请检查IP与端口是否与服务器一致!或者服务器没打开,连接错误,MB_ICONERROR);elseMessageBox(端口或IP输入有误,请重新输入);聊天模块与服务端聊天模块实现原理相同,在此不再重复说明。退出模块与服务器端退出模块实现原理相同,在此不再重复说明。4. 系统测试经过简单的测试,逐个测试每一个功能,系统预想的功能已经全部实现,各个功能能够正常工作,程序最
34、终运行结果见图4.1、4.2所示。图4.1 服务器端运行示意图图4.2 客户端运行示意图5. 总结 本系统实现了基于局域网的一个简单聊天室。在聊天室中客户端不仅可以和服务器端进行一对一的交谈,而且服务器动态监听端口,随时接受其他客户端的连接,可以和多人同时聊天。实现的功能虽然比较简单,但是涉及的核心技术:基于对话框的技术和网络通信技术,都是很重要,很基础的。熟练使用这些技术,对我们的将来的就业有很大的帮助。参考文献1 刘锐宁.软件开发实战1200例:Visual C+开发实战1200例(第1卷)(附光盘).清华大学出版社,2011.01.2 谢希仁计算机网络M.电子工业出版社.2006.08.
35、3 张曾科,古吟东.清华大学计算机基础教育课程系列教材:计算机网络(第3版)M.清华大学出版社,2009.06.4 谭献海.网络编程技术及应用M.清华大学出版社,2008.5 吴礼发.网络程序设计教程M.北京希望电子出版社,2006年6 汪晓平/钟军.Visual C+网络通信协议分析与应用实现M.人民邮电出版社2007年7 (美)JESSICA MULLIGAN,BRIDGETTE PATROVSKY网络游戏开发M.机械工业出版社8 李向丽李磊陈静计算机网络技术与应用M.机械工业出版社2006.089 代勇.Visual C+网络通信编程技术详解.机械工业出版社,2011.05.10 Nicolai M.Josuttis. 侯捷/孟岩译C+标准程序库M.,华中科技大学出版社2001年11 孙鑫.Visual C+深入解析M清华大学出版社,2009.06.