C++面向对象毕业课程设计报告局域网聊天程序.docx

上传人:b****5 文档编号:8308266 上传时间:2023-01-30 格式:DOCX 页数:22 大小:218.95KB
下载 相关 举报
C++面向对象毕业课程设计报告局域网聊天程序.docx_第1页
第1页 / 共22页
C++面向对象毕业课程设计报告局域网聊天程序.docx_第2页
第2页 / 共22页
C++面向对象毕业课程设计报告局域网聊天程序.docx_第3页
第3页 / 共22页
C++面向对象毕业课程设计报告局域网聊天程序.docx_第4页
第4页 / 共22页
C++面向对象毕业课程设计报告局域网聊天程序.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

C++面向对象毕业课程设计报告局域网聊天程序.docx

《C++面向对象毕业课程设计报告局域网聊天程序.docx》由会员分享,可在线阅读,更多相关《C++面向对象毕业课程设计报告局域网聊天程序.docx(22页珍藏版)》请在冰豆网上搜索。

C++面向对象毕业课程设计报告局域网聊天程序.docx

C++面向对象毕业课程设计报告局域网聊天程序

XXXXX大学

C++面向对象课程设计报告

 

院(系):

计算机工程学院

专业:

计算机网络工程

学生姓名:

XXXXXX

班级:

_网络081__ 学号:

题目:

局域网聊天程序

起迄日期:

_2010.12.20–2010.12.31

设计地点:

XX理工大学2#401

指导教师:

XXXXXX

 

完成日期:

2010年12月31日

目录

一需求分析3

1.1客户机端3

1.2服务器端3

二设计内容4

2.1程序整体结构4

2.2各部分子模块功能5

2.3各子模块代码编写6

三调试分析8

3.1实际完成情况8

3.2出现的问题及解决方案8

3.3可以改进的地方9

3.4可以扩充的功能10

四用户手册11

4.1程序主界面11

4.2获取本地信息11

4.3发送信息12

4.4接收信息12

4.5总体演示12

五设计总结13

六参考文献14

七附录15

1需求分析

此次开发的网络聊天工具可作为个人的交流工具使用,通信的安全性不是很高,但要求信息的响应速度要较快,让用户充分享受到网络即时消息的方便和快捷。

本聊天工具由服务器端程序和客户端程序两部分组成,整体采用C++平台开发,没有使用管理数据库。

服务器和与客户端都包含与用户的交互式界面,它有必要的界面的按钮,向用户提供网络即时消息的功能。

本聊天需要包含如下本功能:

1.1客户机端

✓获取本地IP地址

✓获取本地通信端口

✓获取远程IP地址

✓获取本地主机名

✓获取从服务器端发送过来的信息

✓给服务器发送用户自定义的数据

1.2服务器端

✓获取本地IP地址

✓获取本地通信端口

✓获取远程IP地址

✓获取本地主机名

✓获取从服务器端发送过来的信息

✓向客户机发送用户自定义的数据

2设计内容

2.1程序整体结构

2.2各部分子模块功能

2.3各子模块代码编写

1)WM_INITDIALOG模块

switch(UMsg)

{

caseWM_INITDIALOG:

CLIENT.INIT_MYSOCKET(hwndDlg);

===========================================

voidMYSOCKET:

:

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,WM_USER+1,FD_READ);

}

2)IDOK模块

switch(LOWORD(wParam))

{

caseIDOK:

CLIENT.MYSOCK_SEND(hwndDlg);

break;

===========================================

voidMYSOCKET:

:

MYSOCK_SEND(HWND&hwndDlg)

{GetDlgItemText(hwndDlg,IDC_SEND,Buffer,sizeof(Buffer));

sendto(udp_sd,Buffer,strlen(Buffer),0,(structsockaddr*)&Remote_PC,len);

}

3)IDCANCEL模块

caseIDCANCEL:

CLIENT.END_MYSOCKET(hwndDlg);

EndDialog(hwndDlg,0);

break;

===========================================

voidEND_MYSOCKET(HWND&hwndDlg)

{WSAAsyncSelect(udp_sd,hwndDlg,0,0);

closesocket(udp_sd);

WSACleanup();

}

4)FD_READ模块

caseWM_USER+1:

switch(LOWORD(lParam))

{

caseFD_READ:

CLIENT.MYSOCK_RECV(hwndDlg);

break;

}

===========================================

voidMYSOCKET:

:

MYSOCK_RECV(HWND&hwndDlg)

{

recv(udp_sd,Buffer,sizeof(Buffer),0);

SetDlgItemText(hwndDlg,IDC_RECV,Buffer);

}

3调试分析

3.1实际完成情况

经过几天的学习及调试,该“局域网聊天程序”仅仅能实现点对点通信,不能实现一对多、多对多、多对一等通信模式,也就是说,只能开启一个客户机和一个服务器,若有多个程序副本在运行,则可能导致接收以及发送数据的混乱。

用户在输入数据的时候不能包含换行符号,即只能输入一行信息。

用户在接受数据的时候,不能判定它是来自哪台主机。

服务器端不能自动发现上线的客户端,同样客户端也不能自动发现上线的服务器端,两者都是在假设对方在线的前提下发送数据的,这是因为该“局域网聊天程序”是基于UDP协议编写的,它是无连接的协议。

3.2出现的问题及解决方案

1)C++类的封装性

封装就是把对象的属性和操作结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。

通过对抽象结果进行封装,将一部分行为作为外部访问的接口与外部发送联系,而将数据和其他行为进行有效隐藏,就可以达到对数据访问权限的合理控制。

通过这种有效隐藏和合理控制,就可以增强数据的安全性,减轻开发软件系统的难度。

在类中,封装是通过存取权限实现的。

虽然封装性是C++的一个重要特点,但在编写“局域网聊天程序”的时候给我造成了很大的阻碍。

起初我是把负责“接收”、“发送”数据的缓冲变量“Buffer”封装在类中(私有成员),但操作Buffer的函数(如GetDlgItemText、SetDlgItemText)都是在类外访问Buffer变量,开始以为通过return语句把指针传送到对象外就能操作对象里面的Buffer变量,但经过一段时间的测试,程序不能正常运行。

所以我改变了类的封装方式,不但把Buffer变量封装在类里面,而且把操作Buffer变量的函数也封装为类中的某些成员函数,这样就解决了C++类的封装特性给我带来的问题。

2)对象是自动变量

局部变量,如不作专门说明为静态变量,都是动态分配存储空间,存储在动态存储区中。

这种变量叫自动变量。

这种变量只在定义它们的时候才创建,在定义它们的函数返回时系统回收变量所占存储空间。

对这些变量存储空间的分配和回收是由系统自动完成的,所以也叫自动变量。

一般情况下,不作专门说明的局部变量,均是自动变量。

BOOLDialogProc(HWNDhwndDlg,UINTUMsg,WPARAMwParsam,LPARAMlParam)

{

staticMYSOCKETCLIENT(TEXT("127.0.0.1"),4321,TEXT("127.0.0.1"),6321);

switch(UMsg)

{

caseWM_INITDIALOG:

CLIENT.INIT_MYSOCKET(hwndDlg);//初始化套接字

……………………………….

DialogProc函数是系统指定的对话框消息处理回调函数,它是被系统自动地根据用户消息调用。

而且发送给该函数的消息“WM_INITDIALOG”只有在初始化对话框时才被调用,由于局部变量默认是自动变量,所以由MYSOCKET类构造的CLIENT对象在每次系统回调该函数的时候,都会被初始化一遍,而这种操作破坏了套接字与本地信息的绑定,因此服务器端于客户机端程序不能正常通信。

解决这个问题的方法就是使用static操作符使变量变成静态值,使CLIENT对象在函数在多次被调用时,能够维持它的原始值。

即把语句

MYSOCKETCLIENT(TEXT("127.0.0.1"),4321,TEXT("127.0.0.1"),6321);

改变为语句

staticMYSOCKETCLIENT(TEXT("127.0.0.1"),4321,TEXT("127.0.0.1"),6321);

程序正常运行

3)端口冲突

程序给服务器端分配的的端口号是5000,给客户机端分配的端口号是4000。

程序一直运行的很正常,但偶然的一次测试发现程序间不能正常通信,经过反复的调试、测试并没有发现代码中存在什么问题。

我试着改了改端口号服务器端:

6321;客户机端:

4321。

测试通过了。

3.3可以改进的地方

1)用户界面

用VC++开发的界面生硬、死板,并不友好,若能使用一些开发程序皮肤的库文件,使用户界面更加友好。

3.4可以扩充的功能

1)多用户聊天

本程序的逻辑拓扑可以从基于UDP无连接协议的“点对点”拓扑,转化为基于TCP面向连接的“星型”拓扑,以实现多用户之间的回话。

若能采用TCP协议,用户间的通信时通过服务器的转发功能实现的,服务器端程序不修改接收的的信息,只充当“数据转发角色”,把数据按照用户想要传送的目的地发送到目的。

假设客户机A想要把数据发送给客户机B,客户机A先把数据发送给服务器端,然后服务器将数据转发给客户机B,这样对客户机A而言,服务器端是透明的,好像是客户机直接在跟客户机B通信一样。

具体的拓扑如下图所示:

2)自动发现功能

假设服务器端程序在线,当客户端程序上线的时候,服务器端能够自动侦测到客户机端上线,并获取客户机端的用户名、IP地址、通信端口号等必要通信信息,并记录在自己的数据库中登记。

3)文件发送共更能

在聊天功能(即发送字符信息)成功实现的前提下,可以再加入文件传送功能,使这个“局域网聊天程序”的功能更加强大。

4用户手册

4.1程序主界面

虽然本程序是基于客户机/服务器(C/S)模式的通信,但两者的用户界面是一致的,所以在使用上不会给用户带来困难。

服务器端、客户端都包含一个接受信息的控件(IDC_RECV)、一个用于发送信息的控件(IDC_SEND)、一个发送按钮(IDOK)、部分静态文本(IDC_STATIC)、部分本机信息控件(本地主机名(IDC_HOST)、本地IP地址(IDC_IP)、本地端口号(IDC_PORT)、远程IP地址(IDC_IP_REMOTE))。

4.2获取本地信息

服务器端和客户机端的信息是自动获取的,不需要用户干预。

它将自动获取本地主机名、本地IP地址、本地端口号、远程通信IP地址。

下面是在不同计算机上运行客户机端的本地信息截图。

4.3发送信息

只要在“发送:

”下面的控件窗口中填入您想要发送的信息,然后按“发送”按钮,即可发送到远程计算机。

4.4接收信息

客户端、服务器端接收的信息,都会显示在“接收”控件中。

4.5总体演示

1.同时运行UDPClient和UDPServer。

2.在Server端发送“Hello,I’MServer!

”,在Client端发送“Hello,IMClient”。

3.在程序、网络正常的情况下,Server端会接收到Client端发送的信息“Hello,IMClient”;同样,Client端会接收到Server端发送的信息“Hello,I’MServer!

”。

5设计总结

经过两个两个星期的实践学习,使我对C++语言、WINDOWS编程、WINDOWSSOCKET编程有了更进一步的认识和了解,要想学好它重要在实践,要通过不断的上机操作才能更好地学习它,通过实践,我也发现我的好多不足之处,首先是自己在指法上还不行,经常按错字母,通过学习也有所改进;再有对SOCKETAPI中的一些标准函数库不太了解,还有对函数调用的正确使用不够熟悉,还有对C++语言中经常出现的错误也不了解,通过实践,使我在这几个方面的认识有所提高。

通过实践的学习,我认识到学好计算机要重视实践操作,不仅仅是学习C++语言,还是WINDOWS编程,以及其它的计算机方面的知识都要重在实践,所以以后再学习过程中,我会更加注重实践操作,使自己更好地学好计算机。

尤其是在使用SDK编写基于对话框的程序时,接触了全新的WINDOWS的“消息处理”机制。

在参考了众多资料后,成功调试了“局域网聊天程序”的用户界面,这为后期编写SOCKET核心代码提供了基础。

编写通信部分核心代码时,也加深了对“套接字”、“绑定”、“动态链接库”、“端口”等属于的理解。

由于本次设计接触到了两个全新的领域,一是网络通信程序的编写,另一个是C++面向对象程序的编写,为了在开发后期更好的分离错误的出处,我先是用C语言独立编写了网络通信部分、用户界面部分,然后再由C++将其封装为类,但中间的调试花费了我大量的时间,就是因为没有充分理解C++类的封装性与C面向过程程序设计的异同。

所以本次开发使我更好的认识了C++、C、Windows以及网络通信的知识。

通过分析、设计、编码、调试等各环节的训练,深刻理解、C++程序设计技术,掌握分析、解决实际问题的能力。

综合运用所学知识,上机解决一些与实际应用结合紧密的、规模较大的问题,逐步掌握软件开发的基本思想、方法和实现步骤,提高实际应用水平。

这次课程设计基本上含盖了本学期学习到的C++语言知识点,课设题目要求不仅要求对课本知识有较深刻的了解,同时要求程序设计者有较强的动手能力以及自学能力。

这次课设使我了解我编程思想和编程技巧,也认识了软件生命周期的各个环境,包括构思、设计、编写、调试、发布、文档化、维护和修订。

编程的风格也很重要,程序有了良好的编程风格,有良好的程序注释,会在后期调试程序、程序排错过程中获益的;若只关心程序运行的结果,而对程序代码的结构的良好丝毫不在意,是非常不可取的,如果我们希望将来从事编程工作,在这一点上该引起足够的重视。

这是严谨的态度,很重要!

6参考文献

1.JeffreyRichter,ChristopheNasarre.Windows核心编程(第五版).北京:

清华大学出版社.2008.9

2.CharlesPetzold.Windows程序设计(第五版).北京:

北京大学出版社.1999.11

3.KennethA.Reek.C和指针。

北京:

人名邮电出版社.2008.4

4.李兰,任凤华.C++面向对象程序设计.西安:

西安电子科技大学出版社.2010.9

5.W.RichardStevens.TCP/IP详解卷1:

协议.北京:

机械工业出版社.2000.4

6.郑莉.C++语言程序设计(第3版).北京:

清华大学出版社,2005.7

7.钱能.C++程序设计教程(第2版).北京:

清华大学出版社,2005.8

8.谭浩强.C++程序设计.北京:

清华大学出版社.2001

7附录

/////////////////////////////////////////////////////////////////////////

//服务器端与客户机端所使用的类

//COMMON.H

classMYSOCKET

{

public:

/*

**MYSOCKET类构造函数

**1.保存通信端口到成员变量

**A.本地:

Local_Port_Num

**B.远程:

Remote_Port_Num

**

**2.设置通信地址及端口

**A.本地:

127.0.0.1:

local_port

**B.远程:

127.0.0.1:

remote_port

**

**3.获取"structsockaddr"类型长度

*/

MYSOCKET(TCHAR*Local_IP,

WORDlocal_port,

TCHAR*Remote_IP,

WORDremote_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_PC.sin_family=AF_INET;

Remote_PC.sin_addr.s_addr=inet_addr(Remote_IP);

Remote_PC.sin_port=htons(remote_port);

len=sizeof(structsockaddr_in);

}

/*

**初始化套接字

**1.用WSAStartup函数启动网络动态链接库

**2.用socket函数生成UDP套接字

**3.用bind函数将UDP套接字与本机绑定

**4.用WSAAsyncSelect函数注册网络异步选择事件消息

*/

voidINIT_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,WM_USER+1,FD_READ);

}

/*

**发送消息

**1.用GetDlgItemText函数从控件IDC_SEND获取用户即将发送的数据

**2.用sendto函数向目的主机发送UDP数据报

*/

voidMYSOCK_SEND(HWND&hwndDlg)

{

GetDlgItemText(hwndDlg,IDC_SEND,Buffer,sizeof(Buffer));

sendto(udp_sd,Buffer,strlen(Buffer),0,(structsockaddr*)&Remote_PC,len);

}

/*

**接收消息

**1.用recv函数接受数据,并存储于Buffer缓冲区

**2.用SetDlgItemText函数设置控件IDC_RECV,使信息显示在屏幕上

*/

voidMYSOCK_RECV(HWND&hwndDlg)

{

recv(udp_sd,Buffer,sizeof(Buffer),0);

SetDlgItemText(hwndDlg,IDC_RECV,Buffer);

}

/*

**设定本地及远程主机IP

*/

voidMYSOCK_SET_REMOTE(constTCHAR*remote_IP)

{

//功能还未实现

}

/*

**获取本地主机名

**1.将主机名保存于成员变量HOSTNAME中

**2.用wsprintf函数将主机名传送到形参中

*/

voidMYSOCK_GET_HOSTNAME(TCHAR*HOST_BUFFER)

{

gethostname(HOSTNAME,sizeof(HOSTNAME));

wsprintf(HOST_BUFFER,"%s",HOSTNAME);

}

/*

**获取本地通信端口(字符串格式)

**直接用wsprintf函数转换

*/

voidMYSOCKET_GET_PORTNUM(TCHAR*PORT_BUFFER)

{

wsprintf(PORT_BUFFER,"%d",Local_Port_Num);

}

/*

**获取本地通信地址(字符串格式)

**1.用gethostbyname函数取得相关信息

**2.用inet_ntoa函数将网络地址转换为点分字符串形式

**3.用wsprintf函数转换格式并输出

*/

voidMYSOCKET_GET_LOCALIP(TCHAR*IP_BUFFER)

{

HOSTENT=gethostbyname(HOSTNAME);

wsprintf(IP_BUFFER,"%s",inet_ntoa(*(structin_addr*)HOSTENT->h_addr_list[0]));

}

/*

**结束套接字过程

**1.注销网络异步选择事件消息。

**2.关闭套接口

**3.卸载网络动态链接库

*/

voidEND_MYSOCKET(HWND&hwndDlg)

{

WSAAsyncSelect(udp_sd,hwndDlg,0,0);

closesocket(udp_sd);

WSACleanup();

}

private:

/*

**WSADATA以及SOCKET变量

**相关函数:

MYSOCKET:

:

INIT_MYSOCKET(HWND&hwndDlg)

*/

WSADATAwsaData;

SOCKETudp_sd;

/*

**1.Local_Port_Num==>本地端口号

**Remote_Port_Num==>目的端口号

**

**2.Local_PC==>本地通信结构

**Remote_PC==>远程通信结构

**

**3.len==>"structsockaddr"类型的长度

**

**相关函数:

MYSOCKET:

:

MYSOCKET(WORDlocal_port,WORDremote_port)

*/

WORDLocal_Port_Num,Remote_Port_Num;

structsockaddr_inLocal_PC,Remote_PC;

intlen;

/*

**数据接收、发送缓冲区

**相关函数:

MYSOCKET:

:

MYSOCK_RECV(HWND&hwndDlg)

**MYSOCKET:

:

MYSOCK_SEND(HWND&hwndDlg)

**

*/

TCHARBuffer[100];

/*

**保存本地主机名

**相关函数:

MYSO

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 互联网

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1