C面向对象课程方案设计书报告(局域网聊天程序)_第1页
C面向对象课程方案设计书报告(局域网聊天程序)_第2页
C面向对象课程方案设计书报告(局域网聊天程序)_第3页
C面向对象课程方案设计书报告(局域网聊天程序)_第4页
C面向对象课程方案设计书报告(局域网聊天程序)_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、XXXXX大学C+面向对象课程设计报告院(系): 计算机工程学院 专业: 计算机网络工程 学生姓名: XXXXXX 班级:网络081学号: 200807255 题目: 局域网聊天程序 起迄日期: 2010.12.20 2010.12.31 设计地点: XX理工大学2#401 指 导 教 师: XXXXXX 完成日期: 2010 年 12 月 31 日目录一 需求分析31.1 客户机端31.2 服务器端3二 设计内容42.1 程序整体结构42.2 各部分子模块功能52.3 各子模块代码编写6三 调试分析83.1 实际完成情况83.2 出现的问题及解决方案83.3 可以改进的地方93.4 可以扩充

2、的功能10四 用户手册114.1 程序主界面114.2 获取本地信息114.3 发送信息124.4 接收信息124.5 总体演示12五 设计总结13六 参考文献14七 附录151 需求分析此次开发的网络聊天工具可作为个人的交流工具使用,通信的安全性不是很高,但要求信息的响应速度要较快,让用户充分享受到网络即时消息的方便和快捷。本聊天工具由服务器端程序和客户端程序两部分组成,整体采用C+平台开发,没有使用管理数据库。服务器和与客户端都包含与用户的交互式界面,它有必要的界面的按钮,向用户提供网络即时消息的功能。本聊天需要包含如下本功能:1.1 客户机端 获取本地IP地址 获取本地通信端口 获取远程

3、IP地址 获取本地主机名 获取从服务器端发送过来的信息 给服务器发送用户自定义的数据1.2 服务器端 获取本地IP地址 获取本地通信端口 获取远程IP地址 获取本地主机名 获取从服务器端发送过来的信息 向客户机发送用户自定义的数据2 设计内容2.1 程序整体结构WinMain()(主函数)DialogBoxParam()(生成对话框)DialogProc()(对话框消息处理函数)消息队列用户操作(点击确定、点击关闭)WM_INITDIALOG(对话框初始化)WM_COMMAND(用户命令)WM_USE+1(用注册消息)IDOK(用户点击确定)IDCANCEL(用户点击关闭)FD_READ(读取

4、信息消息)2.2 各部分子模块功能WM_INITDIALOG(对话框初始化)IDOK(用户点击确定)IDCANCEL(用户点击关闭)FD_READ(读取信息消息)WSAStartup()(启动网络动态链接库)Socket()(产生套接字)Bind()(套接字绑定)WSAAsyncSelect()(注册自定义网络消息)Sendto()(向远程主机发送信息)Recv()(接收远程数据)GetDlgItemText()(获取用户的信息输入)SetDlgItemText()(设定对话框控件数据)WSAAsyncSelect()注册自定义网络消息Closesocket()关闭套接字WSACLeanup(

5、)(卸载网络动态链接库)2.3 各子模块代码编写1) WM_INITDIALOG模块switch(UMsg)case WM_INITDIALOG:CLIENT.INIT_MYSOCKET(hwndDlg);=void MYSOCKET:INIT_MYSOCKET(HWND &hwndDlg) WSAStartup(0x0101, &wsaData);udp_sd=socket(AF_INET, SOCK_DGRAM, 0);bind(udp_sd, (LPSOCKADDR)&Local_PC, sizeof(Local_PC);WSAAsyncSelect(udp_sd, hwndDlg, W

6、M_USER+1, FD_READ);2) IDOK模块switch(LOWORD(wParam)case IDOK:CLIENT.MYSOCK_SEND(hwndDlg);break;=void MYSOCKET:MYSOCK_SEND(HWND &hwndDlg) GetDlgItemText(hwndDlg, IDC_SEND, Buffer, sizeof(Buffer);sendto(udp_sd, Buffer, strlen(Buffer), 0, (struct sockaddr *)&Remote_PC, len); 3) IDCANCEL模块case IDCANCEL:CL

7、IENT.END_MYSOCKET(hwndDlg);EndDialog(hwndDlg, 0);break;=void END_MYSOCKET(HWND &hwndDlg) WSAAsyncSelect(udp_sd, hwndDlg, 0, 0);closesocket(udp_sd);WSACleanup(); 4) FD_READ模块case WM_USER+1:switch(LOWORD(lParam)case FD_READ:CLIENT.MYSOCK_RECV(hwndDlg);break;=void MYSOCKET:MYSOCK_RECV(HWND &hwndDlg)rec

8、v(udp_sd, Buffer, sizeof(Buffer), 0);SetDlgItemText(hwndDlg, IDC_RECV, Buffer);3 调试分析3.1 实际完成情况经过几天的学习及调试,该“局域网聊天程序”仅仅能实现点对点通信,不能实现一对多、多对多、多对一等通信模式,也就是说,只能开启一个客户机和一个服务器,若有多个程序副本在运行,则可能导致接收以及发送数据的混乱。用户在输入数据的时候不能包含换行符号,即只能输入一行信息。用户在接受数据的时候,不能判定它是来自哪台主机。服务器端不能自动发现上线的客户端,同样客户端也不能自动发现上线的服务器端,两者都是在假设对方在线的

9、前提下发送数据的,这是因为该“局域网聊天程序”是基于UDP协议编写的,它是无连接的协议。3.2 出现的问题及解决方案1) C+类的封装性封装就是把对象的属性和操作结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。通过对抽象结果进行封装,将一部分行为作为外部访问的接口与外部发送联系,而将数据和其他行为进行有效隐藏,就可以达到对数据访问权限的合理控制。通过这种有效隐藏和合理控制,就可以增强数据的安全性,减轻开发软件系统的难度。在类中,封装是通过存取权限实现的。虽然封装性是C+的一个重要特点,但在编写“局域网聊天程序”的时候给我造成了很大的阻碍。起初我是把负责“接收”、“发送”数据的缓冲变量“B

10、uffer”封装在类中(私有成员),但操作Buffer的函数(如GetDlgItemText、 SetDlgItemText)都是在类外访问Buffer变量,开始以为通过return语句把指针传送到对象外就能操作对象里面的Buffer变量,但经过一段时间的测试,程序不能正常运行。所以我改变了类的封装方式,不但把Buffer变量封装在类里面,而且把操作Buffer变量的函数也封装为类中的某些成员函数,这样就解决了C+类的封装特性给我带来的问题。2) 对象是自动变量局部变量,如不作专门说明为静态变量,都是动态分配存储空间,存储在动态存储区中。这种变量叫自动变量。这种变量只在定义它们的时候才创建,在

11、定义它们的函数返回时系统回收变量所占存储空间。对这些变量存储空间的分配和回收是由系统自动完成的,所以也叫自动变量。一般情况下,不作专门说明的局部变量,均是自动变量。BOOL DialogProc(HWND hwndDlg,UINT UMsg,WPARAM wParsam,LPARAM lParam)static MYSOCKET CLIENT(TEXT(), 4321, TEXT(), 6321);switch(UMsg)case WM_INITDIALOG: CLIENT.INIT_MYSOCKET(hwndDlg); /初始化套接字.DialogProc

12、函数是系统指定的对话框消息处理回调函数,它是被系统自动地根据用户消息调用。而且发送给该函数的消息“WM_INITDIALOG”只有在初始化对话框时才被调用,由于局部变量默认是自动变量,所以由MYSOCKET类构造的CLIENT对象在每次系统回调该函数的时候,都会被初始化一遍,而这种操作破坏了套接字与本地信息的绑定,因此服务器端于客户机端程序不能正常通信。解决这个问题的方法就是使用static操作符使变量变成静态值,使CLIENT对象在函数在多次被调用时,能够维持它的原始值。即把语句MYSOCKET CLIENT(TEXT(), 4321, TEXT(), 6

13、321);改变为语句static MYSOCKET CLIENT(TEXT(), 4321, TEXT(), 6321);程序正常运行3) 端口冲突程序给服务器端分配的的端口号是5000, 给客户机端分配的端口号是4000。程序一直运行的很正常,但偶然的一次测试发现程序间不能正常通信,经过反复的调试、测试并没有发现代码中存在什么问题。我试着改了改端口号服务器端:6321;客户机端:4321。测试通过了。3.3 可以改进的地方1) 用户界面用VC+开发的界面生硬、死板,并不友好,若能使用一些开发程序皮肤的库文件,使用户界面更加友好。3.4 可以扩充的功能1)

14、多用户聊天本程序的逻辑拓扑可以从基于UDP无连接协议的“点对点”拓扑,转化为基于TCP面向连接的“星型”拓扑,以实现多用户之间的回话。若能采用TCP协议,用户间的通信时通过服务器的转发功能实现的,服务器端程序不修改接收的的信息,只充当“数据转发角色”,把数据按照用户想要传送的目的地发送到目的。假设客户机A想要把数据发送给客户机B,客户机A先把数据发送给服务器端,然后服务器将数据转发给客户机B,这样对客户机A而言,服务器端是透明的,好像是客户机直接在跟客户机B通信一样。具体的拓扑如下图所示:2) 自动发现功能假设服务器端程序在线,当客户端程序上线的时候,服务器端能够自动侦测到客户机端上线,并获取

15、客户机端的用户名、IP地址、通信端口号等必要通信信息,并记录在自己的数据库中登记。3) 文件发送共更能在聊天功能(即发送字符信息)成功实现的前提下,可以再加入文件传送功能,使这个“局域网聊天程序”的功能更加强大。4 用户手册4.1 程序主界面虽然本程序是基于客户机/服务器(C/S)模式的通信,但两者的用户界面是一致的,所以在使用上不会给用户带来困难。服务器端、客户端都包含一个接受信息的控件(IDC_RECV)、一个用于发送信息的控件(IDC_SEND)、一个发送按钮(IDOK)、部分静态文本(IDC_STATIC)、部分本机信息控件(本地主机名(IDC_HOST)、本地IP地址(IDC_IP)

16、、本地端口号(IDC_PORT)、远程IP地址(IDC_IP_REMOTE)。 4.2 获取本地信息服务器端和客户机端的信息是自动获取的,不需要用户干预。它将自动获取本地主机名、本地IP地址、本地端口号、远程通信IP地址。下面是在不同计算机上运行客户机端的本地信息截图。 4.3 发送信息只要在“发送:”下面的控件窗口中填入您想要发送的信息,然后按“发送”按钮,即可发送到远程计算机。4.4 接收信息客户端、服务器端接收的信息,都会显示在“接收”控件中。4.5 总体演示1. 同时运行UDP Client和UDP Server。2. 在Server端发送“Hello, IM Server!”,在Cl

17、ient端发送“Hello, IM Client”。3. 在程序、网络正常的情况下,Server端会接收到Client端发送的信息“Hello, IM Client”;同样,Client端会接收到Server端发送的信息“Hello, IM Server!”。 5 设计总结经过两个两个星期的实践学习,使我对C+语言、WINDOWS编程、WINDOWS SOCKET编程有了更进一步的认识和了解,要想学好它重要在实践,要通过不断的上机操作才能更好地学习它,通过实践,我也发现我的好多不足之处,首先是自己在指法上还不行,经常按错字母,通过学习也有所改进;再有对SOCKET API中的一些标准函数库不太

18、了解,还有对函数调用的正确使用不够熟悉,还有对C+语言中经常出现的错误也不了解,通过实践,使我在这几个方面的认识有所提高。通过实践的学习,我认识到学好计算机要重视实践操作,不仅仅是学习C+语言,还是WINDOWS编程,以及其它的计算机方面的知识都要重在实践,所以以后再学习过程中,我会更加注重实践操作,使自己更好地学好计算机。尤其是在使用SDK编写基于对话框的程序时,接触了全新的WINDOWS的“消息处理”机制。在参考了众多资料后,成功调试了“局域网聊天程序”的用户界面,这为后期编写SOCKET核心代码提供了基础。编写通信部分核心代码时,也加深了对“套接字”、“绑定”、“动态链接库”、“端口”等

19、属于的理解。由于本次设计接触到了两个全新的领域,一是网络通信程序的编写,另一个是C+面向对象程序的编写,为了在开发后期更好的分离错误的出处,我先是用C语言独立编写了网络通信部分、用户界面部分,然后再由C+将其封装为类,但中间的调试花费了我大量的时间,就是因为没有充分理解C+类的封装性与C面向过程程序设计的异同。所以本次开发使我更好的认识了C+、C、Windows以及网络通信的知识。通过分析、设计、编码、调试等各环节的训练,深刻理解、C+程序设计技术,掌握分析、解决实际问题的能力。综合运用所学知识,上机解决一些与实际应用结合紧密的、规模较大的问题,逐步掌握软件开发的基本思想、方法和实现步骤,提高

20、实际应用水平。这次课程设计基本上含盖了本学期学习到的C+语言知识点,课设题目要求不仅要求对课本知识有较深刻的了解,同时要求程序设计者有较强的动手能力以及自学能力。这次课设使我了解我编程思想和编程技巧,也认识了软件生命周期的各个环境,包括构思、设计、编写、调试、发布、文档化、维护和修订。编程的风格也很重要,程序有了良好的编程风格,有良好的程序注释,会在后期调试程序、程序排错过程中获益的;若只关心程序运行的结果,而对程序代码的结构的良好丝毫不在意,是非常不可取的,如果我们希望将来从事编程工作,在这一点上该引起足够的重视。这是严谨的态度,很重要!6 参考文献1. Jeffrey Richter,Ch

21、ristophe Nasarre. Windows核心编程(第五版). 北京:清华大学出版社. 2008.92. Charles Petzold. Windows程序设计(第五版). 北京:北京大学出版社. 1999.113. Kenneth A.Reek. C和指针。 北京:人名邮电出版社. 2008.44. 李兰,任凤华. C+面向对象程序设计. 西安:西安电子科技大学出版社. 2010.95. W.Richard Stevens. TCP/IP详解 卷1:协议. 北京:机械工业出版社. 2000.46. 郑莉C+语言程序设计(第3版)北京:清华大学出版社,2005.77. 钱能C+程序设

22、计教程(第2版)北京:清华大学出版社,2005.88. 谭浩强. C+程序设计. 北京:清华大学出版社. 20017 附录/ 服务器端与客户机端所使用的类/ COMMON.Hclass MYSOCKETpublic:/*MYSOCKET类构造函数* 1.保存通信端口到成员变量* A.本地:Local_Port_Num* B.远程:Remote_Port_Num* 2.设置通信地址及端口* A.本地::local_port* B.远程::remote_port* 3.获取struct sockaddr类型长度*/MYSOCKET(TCHAR *Local_IP

23、,WORD local_port,TCHAR *Remote_IP, WORD remote_port)Local_Port_Num=local_port;Remote_Port_Num=remote_port;memset(&Local_PC, 0, sizeof(Local_PC);Local_PC.sin_family=AF_INET;Local_PC.sin_addr.s_addr=inet_addr(Local_IP);Local_PC.sin_port=htons(local_port);memset(&Remote_PC, 0, sizeof(Remote_PC);Remote_

24、PC.sin_family=AF_INET;Remote_PC.sin_addr.s_addr=inet_addr(Remote_IP);Remote_PC.sin_port=htons(remote_port);len=sizeof(struct sockaddr_in);/*初始化套接字* 1.用WSAStartup函数启动网络动态链接库* 2.用socket函数生成UDP套接字* 3.用bind函数将UDP套接字与本机绑定* 4.用WSAAsyncSelect函数注册网络异步选择事件消息*/void INIT_MYSOCKET(HWND &hwndDlg)WSAStartup(0x010

25、1, &wsaData);udp_sd=socket(AF_INET, SOCK_DGRAM, 0);bind(udp_sd, (LPSOCKADDR)&Local_PC, sizeof(Local_PC);WSAAsyncSelect(udp_sd, hwndDlg, WM_USER+1, FD_READ);/*发送消息* 1.用GetDlgItemText函数从控件IDC_SEND获取用户即将发送的数据* 2.用sendto函数向目的主机发送UDP数据报*/void MYSOCK_SEND(HWND &hwndDlg)GetDlgItemText(hwndDlg, IDC_SEND, Bu

26、ffer, sizeof(Buffer);sendto(udp_sd, Buffer, strlen(Buffer), 0, (struct sockaddr *)&Remote_PC, len);/*接收消息* 1.用recv函数接受数据,并存储于Buffer缓冲区* 2.用SetDlgItemText函数设置控件IDC_RECV,使信息显示在屏幕上*/void MYSOCK_RECV(HWND &hwndDlg)recv(udp_sd, Buffer, sizeof(Buffer), 0);SetDlgItemText(hwndDlg, IDC_RECV, Buffer);/*设定本地及远

27、程主机IP*/void MYSOCK_SET_REMOTE(const TCHAR *remote_IP)/功能还未实现/*获取本地主机名* 1.将主机名保存于成员变量HOSTNAME中* 2.用wsprintf函数将主机名传送到形参中*/void MYSOCK_GET_HOSTNAME(TCHAR *HOST_BUFFER)gethostname(HOSTNAME, sizeof(HOSTNAME);wsprintf(HOST_BUFFER, %s, HOSTNAME);/*获取本地通信端口(字符串格式)* 直接用wsprintf函数转换*/void MYSOCKET_GET_PORTNUM

28、(TCHAR *PORT_BUFFER)wsprintf(PORT_BUFFER, %d, Local_Port_Num);/*获取本地通信地址(字符串格式)* 1.用gethostbyname函数取得相关信息* 2.用inet_ntoa函数将网络地址转换为点分字符串形式* 3.用wsprintf函数转换格式并输出*/void MYSOCKET_GET_LOCALIP(TCHAR *IP_BUFFER)HOSTENT=gethostbyname(HOSTNAME);wsprintf(IP_BUFFER, %s, inet_ntoa(*(struct in_addr *)HOSTENT-h_ad

29、dr_list0);/*结束套接字过程* 1.注销网络异步选择事件消息。* 2.关闭套接口* 3.卸载网络动态链接库*/void END_MYSOCKET(HWND &hwndDlg)WSAAsyncSelect(udp_sd, hwndDlg, 0, 0);closesocket(udp_sd);WSACleanup();private:/*WSADATA以及SOCKET变量* 相关函数:MYSOCKET:INIT_MYSOCKET(HWND &hwndDlg)*/WSADATAwsaData;SOCKET udp_sd;/*1.Local_Port_Num = 本地端口号* Remote_

30、Port_Num = 目的端口号*2.Local_PC = 本地通信结构* Remote_PC = 远程通信结构*3.len = struct sockaddr类型的长度* 相关函数:MYSOCKET:MYSOCKET(WORD local_port,WORD remote_port)*/WORD Local_Port_Num, Remote_Port_Num;struct sockaddr_in Local_PC, Remote_PC;int len;/*数据接收、发送缓冲区* 相关函数:MYSOCKET:MYSOCK_RECV(HWND &hwndDlg)* MYSOCKET:MYSOCK

31、_SEND(HWND &hwndDlg)*/TCHAR Buffer100;/*保存本地主机名* 相关函数:MYSOCKET:MYSOCK_GET_HOSTNAME(TCHAR *HOST_BUFFER)*/TCHAR HOSTNAME10;/* * struct hostent*char FAR * h_name;*char FAR * FAR * h_aliases;*short h_addrtype;*short h_length;*char FAR * FAR * h_addr_list;*;*/struct hostent *HOSTENT;/ 服务器端源代码/ SERVER.CPP

32、#include #include #include .SERVERresource.h#include .COMMON.H/TCHAR PORT_BUFFER10;TCHAR HOST_BUFFER10;TCHAR IP_BUFFER20;/TCHAR IP_REMOTE_BUFFER20;/BOOL DialogProc(HWND hwndDlg,UINT UMsg,WPARAM wParam,LPARAM IParam);/int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, i

33、nt nShowCmd)DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_SERVER), NULL, (DLGPROC)DialogProc, 0);return 0;/BOOL DialogProc(HWND hwndDlg,UINT UMsg,WPARAM wParam,LPARAM lParam)/*!构造静态CLIENT对象!* 1.本地::4321* 2.远程::6321*/static MYSOCKET SERVER(TEXT(), 4321, TEXT(), 6321);switch(UMsg)case WM_INITDIALOG:/*初始化套接字*/SERVER.INIT_MYSOCKET(hwndDlg);/*1.将本地IP地址保存于IP_BUFFER变量*2.将其显示在IDC_IP控件中*/SERVER.MYSOCKET_GET_LOCALIP(IP_BUFFER);SetDlgItemText(hwndDlg, IDC_IP, IP_BUFFER);/*1.将本地主机名保存于HOST_BUFFER变量*2.将其

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论