局域网聊天程序MFC 课程设计_第1页
局域网聊天程序MFC 课程设计_第2页
局域网聊天程序MFC 课程设计_第3页
局域网聊天程序MFC 课程设计_第4页
局域网聊天程序MFC 课程设计_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

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

文档简介

1、第1章 绪论1、背景介绍 随着网路的出现,它在人们的生活中所扮演的角色越来越多,也越来越重要,人们可以通过这个空间进行网络聊天,实现彼此沟通,交换信息,甚至网络聊天工具在部分人的生活中由于传统的电话通讯手段同等重要的趋势。尤其现在的学校更是如此,单单在课堂里或校园里的交流是远远不够的,要是学校有聊天系统,那么学生之间或是师生之间的信息交流会更加频繁、更方便,有利于建立友好的关系网。本次局域网即时聊天程序设计主要用了Visual C+编程环境,设计里还涉及到了网络通信基本原理UDP和Socket编程技术。由于程序是在UDP/IP环境下运行,所以分无需建立连接。用户之间是通过建立Socket链接来

2、实现聊天功能。2、相关知识1.2.1 Visual C+ 简介Visual C+是一个功能强大的可视化应用程序开发工具,用于Windows环境下32位的应用程序的开发,是计算机界公认的最优秀的应用开发工具之一。在提供可视化的编程方式的同时,Visual C+也适用于编写直接对系统底层操作的程序,生成代码的质量也优于其它的开发工具。在Visual C+环境下,利用Microsoft的基本类库MFC(Microsoft Foundation Class Library),可以使用完全的面向对象的方法来进行Windows 95/98/NT应用程序的开发,使得Windows程序员从大量的复杂劳动中解救

3、出来,体会到真正的程序语言的强大功能和良好的灵活性。Visual C+编程是一个面向对象的程序设计方法。同传统的结构化程序设计方法相比,它缩短软件的研制时间,提高软件的开发效率,使程序员可以更好地理解和管理庞大而复杂的程序。面向对象的程序设计吸取了结构化程序设计的精华,它利用了人们根据对事物分类和抽象的倾向,引入了类和对象的概念,具有封装性(数据抽象)、继承和多态的特点。与结构化程序设计不同的是,面向对象程序设计是用类抽象代表现实的实体,用类之间的继承关系表示程序设计的抽象过程。函数只是对数据的操作,没有数据的概念,而类是数据和数据操作的集合,由于面向对象的程序设计方法非常近现实,所以越来越流

4、行。Visual C+中集成了大量的最新技术,如ActiveX、COM等技术,程序开发人员可以紧紧地把握住软件开发技术发展的方向,开发出功能强大的应用程序。Visual C+还提供了丰富的技术资源,MSDN(Microsoft Develop Network)提供了强大的联机帮助支持,同时还可以通过访问Microsoft的网上站点来获得最新的技术文档。1.2.2 Socket 套接字(Socket)是一种双向的通信接口,可以通过这个端口与任何一个具有Socket端口的计算机通信,套接字是网络通信的基础。Socket在Windows以句柄的形式被创建。使用Socket进行网络通信必须包含下面的几

5、种信息:双方认可的协议,本地主机的IP地址,本地进程的协议端口,对方主机的IP地址,对方进程的协议端口。 Socket可分为: 1 数据报套接字(Datagram Sockets) 对于在TCP/IP上实现的WinSock,数据报套接字使用用户数据报协议(UDP)。数据报套接字提供了一种不可靠的、非连接的数据包通信方式。 2 流式套接字(Stream Sockets) 流式套接字使用传输控制协议(TCP)。流式套接字可以将数据按顺序无重复地发送到目的地,它提供的是一种可靠的、面向连接的数据传输方式。不管是对单个的数据报,还是对数据包,流式套接字都提供了一种流式数据传输。1.2.3 MFC So

6、cket编程技术 Sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);基于TCP的socket编程是采用的流式套接字。在这个程序中,将两个工程添加到一个工作区。要链接一个ws2_32.lib的库文件。程序编程的步骤:1:加载套接字库,创建套接字(AsfSocket()/socket();2:绑定套接字到一个IP地址和一个端口上(bind();3:将套接字设置为监听模式等待连接请求(listen();4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept();5:用返回的套接字和客

7、户端进行通信(send()/recv();6:返回,等待另一连接请求;7:关闭套接字,关闭加载的套接字库(closesocket()。1.2.4socket函数socket的创建函数,其定义为:SOCKET PASCAL FAR socket (int af, int type, int protocol)第一个参数为int af,代表网络地址族,目前只有一种取值是有效的,即AF_INET,代表internet地址族;第二个参数为int type,代表网络协议类型,SOCK_DGRAM代表UDP协议,SOCK_STREAM代表TCP协议;第三个参数为int protocol,指定网络地址族的特

8、殊协议,目前无用,赋值0即可。返回值为SOCKET,若返回INVALID_SOCKET则失败。1.2.5sockaddr_in、in_addr类型,inet_addr、inet_ntoa函数sockaddr_in定义了socket发送和接收数据包的地址sockaddr_in的含义比in_addr的含义要广泛,其各个字段的含义和取值如下第一个字段short sin_family,代表网络地址族,如前所述,只能取值AF_INET;第二个字段u_short sin_port,代表IP地址端口,由程序员指定;第三个字段struct in_addr sin_addr,代表IP地址;第四个字段char&#

9、160;   sin_zero8,很搞笑,是为了保证sockaddr_in与SOCKADDR类型的长度相等而填充进来的字段。 第2章 需求分析2.1 需求分析 在这里先说明设计的需求分析之前分析一下设计的可行性。可行性分析的目的是为了用最小代价在最短时间内确定问题是否能够解决。可行性分析的实质就是要进行一次压缩简化系统分析和设计的过程,也就是在较高层次上以较抽象的方式进行的系统分析和设计的过程。2.1.1 可行性分析1) 技术可行性:本系统以Visual C+为主要编程环境,再结合网络通信UDP原理和Socket编程,技术成熟,可行。2) 经济可行性:这个系统开发开发成本较

10、低,经济效益会远大于开发成本,可行。3) 操作可行性:系统硬件为PC机,而且编程环境Visual C+为专业程序员使用工具,比较易于使用,可行。2.1.2 需求分析需求分析的基本任务是准确的回答“系统必须做什么?”这个问题。这一阶段是对系统认识最为全面、准确、清晰、得体的一个比较关键的时期。而且需求分析的结果是系统开发的基础,关系到工程的成败和软件产品的质量。因此,必须用行之有效的方法对软件需求进行严格的审查验证,为下一步的总体设计打好基础。本次设计的局域网聊天程序是基于网络通信的UDP/IP协议,本程序既是服务器端又是客户端,用户在局域网内利用本软件进行聊天时不需要先进行连接,只需输入对方的

11、IP,如果对方PC机上运行着该软件即可进行通信,软件界面可以比较简单,可以发送和接受来自局域网的信息,聊天人数可以不限,一般就是实现单对单的局域网里的聊天,程序实现起来比较的简单。本次设计的聊天程序仅仅局限于文字聊天,着重加强对C+知识的运用和理解以及MFC编程的认识:系统的功能要求:文本聊天就是在线双方互相传递文本信息的功能。下面是文本聊天部分所要完成的功能。1)在这个系统中只要在线即双方局域网内的主机都运行该程序就可以和在线的朋友进行聊天,并且为不同的朋友提供的是相同的聊天窗口,也就是说和几个或多个在线人员聊天的话只有一个聊天窗口打开。2)与特定用户之间的聊天窗口中必须提供聊天信息的输入和

12、聊天信息的显示功能,前提是IP是对方的主机地址。3)要发送给对方的文字或字符的输入工作要在聊天窗口的输入框中完成。4)当输入完聊天信息以后进行发送,当发送没有结束时,不能进行新的聊天内容的输入。一般聊天内容一次不能超过200个字符。5) 聊天信息要显示在聊天窗口中,显示的内容包括:接收信息。发送的信息未曾设计在内,在后面的补充中得以改进。发送信息是指自己发送给对方的信息,即发送内容;接收信息是指来自对方的信息,这里显示接收到的内容。 第3章 设计内容经过了需求分析阶段的工作,系统必须“做什么”的问题已经清楚了,现在是决定“怎么做”的时候了。总体设计的基本目的就是回答“系统应该如何实现?”这个问

13、题。在这里要确定系统中每个程序是由哪些模块组成的,以及这些模块相互间的关系。3.1 模块图根据本次设计需要,聊天程序完成本局域网内的文字聊天功能。有需求分析阶段的分析可根据输入的本局域网内的IP地址完成通信功能,那么本程序的模块可主要由IP地址块、文字输入、发送、接收文字信息等四个模块组成。其中IP地址块是为了获取本地局域网内的IP地址,这样基于ip的UDP协议通信可以简单实现:局域网即时文字聊天 编辑发送窗口编辑接收窗口发送获取对方IP3.2主程序及其主要模块的流程图UDP使用无连接的套接字,不需要在网络设备之间发送连接信息,一个程序即使客户端又是服务器端,那么一个设备最初在等待信息时,套接

14、字就必须用Bind绑定到一个本地“IP地址/端口”上,完成绑定就可以利用套接字收发数据了:函数之间的相互关系:主机1 主机2Socket()Bind()Sendto()RecvFrom()Close()Socket()Bind()RecvFrom()Sendto()程序流程图: 开始 套接字创建N 弹出窗口提示“套接字创建失败” Y 返回FALSE获取IP地址信息端口绑定发送信息利用套接字创建UDP数据报数据传输绑定失败完毕3.3程序代码(主要模块的实现函数) 1、局域网聊天程序首先要加载套接字库,在函数CWinApp:InitInstance中进行声明BOOL CChatApp:InitIn

15、stance()if(!AfxSocketInit()AfxMessageBox("加载套接字库失败!");/如果套接字协商失败,提示用户return FALSE;注意进行套接字库加载时首先要声明头文件”#include<Afxsock.h>”中,在MFC编程中所有头文件都包含在预编译"stdafx.h"头文件中,所以每个MFC程序都要有一个"stdafx.h"头文件。2、套接字的初始化,在CChatDlg中插入一个类型为BOOL的InitSocket()函数,完成套接字的初始化操作;插入一个成员private的成员函数m

16、_socket(套接字描述符)。BOOL CChatDlg:InitSocket()m_socket=socket(AF_INET,SOCK_DGRAM,0);/利用socket创建一个套接字,基于UDP的协议 创建数据报if(INVALID_SOCKET =m_socket) MessageBox("套接字创建失败!"); return FALSE;/利用套接字的返回值判断套接字是否创建成功SOCKADDR_IN addrSock;/绑定一个IP地址或是端口定义一个地址结构体的变量addrSock.sin_family=AF_INET;addrSock.sin_port=

17、htons(6000);/设定端口addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);/指定IP地址,接受发送到本地任意ip地址的数据int retval;retval=bind (m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR); if(SOCKET_ERROR=retval)closesocket(m_socket);MessageBox("绑定失败!");return FALSE;/利用bind函数的返回值判断套接字是否绑定成功return TRUE;完成初始化操作后在On

18、InitDialog()函数中声明InitSocket();。3、接收端程序的书写如果没有数据接收那么recvfrom函数就会阻塞,程序就会暂停运行,所以把接收操作放到一个单独线程中运行,创建线程可用CreateThread函数,创建了一个线程之后就要对它传递两个参数:一个是创建的套接字,另一个是对话框的句柄(接受编辑框的句柄)。由于CreateThread函数只提供了一个参数(指针类型),那么要传递两个参数,可先定义一个结构体(有两个成员),传递这个结构体的指针结构体的定义:struct RECVPARAM SOCKET sock;HWND hwnd;然后在OnInitDialog()中定义

19、一个RECVPARAM的指针对结构体成员进行初始化:RECVPARAM *pRecvParam=new RECVPARAM;pRecvParam->sock=m_socket;pRecvParam->hwnd=m_hWnd;/结构体成员的初始化 创建一个线程:HANDLE hThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);/创建一个线程 第四个参数要强制类型转化一下 CloseHandle(hThread); 写线程函数:ThreadProc可写在OnInitDialog()之上声明为一个全局的函数,但在

20、面向对象的C+编程中,通常不声明全局函数,可在CChatDlg中声明一个函数把它定义为Static,静态函数:DWORD WINAPI CChatDlg: RecvProc(LPVOID lpParameter)函数实现:SOCKET sock=(RECVPARAM*)lpParameter)->sock;HWND hwnd=(RECVPARAM*)lpParameter)->hwnd;/取出定义的两个数据SOCKADDR_IN addrFrom;/接受发送端的地址信息int len=sizeof(SOCKADDR);char recvBuf200; /接受到来的数据char te

21、mpBuf300; /存放格式化的数据int retval;while(TRUE)retval=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);if(SOCKET_ERROR=retval)break;/根据recvfrom的返回值是否出错sprintf(tempBuf,"%s说: %s",inet_ntoa(addrFrom.sin_addr),recvBuf);/接收到的数据进行格式化, inet_ntoa(addrFrom.sin_addr)是将地址转化成点分十进制的格式:PostMessa

22、ge(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);/接收数据传给对话框return 0; 还要对消息的值先定义:#define WM_RECVDATA WM_USER+1 接下来要对消息响应函数原型进行声明: afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);/消息响应函数的原型声明(传递消息时要带参数,所以消息响应函数要带参数) 消息映射:ON_MESSAGE(WM_RECVDATA,OnRecvData)/消息映射 最后消息响应函数的实现:void CChatDlg:OnRecvData(WPARAM wP

23、aram,LPARAM lParam)CString str=(char*)lParam;/用于接受新的数据CString strTemp;/用于接受旧的数据GetDlgItemText(IDC_EDIT_RECV,strTemp);/获取数据str+="rn"str+=strTemp;SetDlgItemText(IDC_EDIT_RECV,str);/ 将数据在接受框显示4、发送端程序的书写 首先生成按钮点击事件的函数:获取主机IP是由CIPAddressCtrl类GetAddress函数完成:void CChatDlg:OnBtnSend() / TODO: Add

24、your control notification handler code hereDWORD dwIP;(CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1)->GetAddress(dwIP);/转化类型,获取主机IP字节序SOCKADDR_IN addrTo;addrTo.sin_family=AF_INET;addrTo.sin_port=htons(6000);/要有相同的端口号addrTo.sin_addr.S_un.S_addr=htonl(dwIP);/转化成网络的字节序 CString strSend; /得到要发送的数据GetDlgI

25、temText(IDC_EDIT_SEND,strSend);sendto(m_socket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR);/发送数据SetDlgItemText(IDC_EDIT_SEND,"");/把发送窗口置空5、 MFC对话框过程 MFC对话框过程AfxDlgProc的原型和实现如下:BOOL CALLBACK AfxDlgProc(HWND hWnd,UINT message, PARAM, LPARAM)if (message = WM_INITDI

26、ALOG)/处理WM_INITDIALOG消息CDialog* pDlg = DYNAMIC_DOWNCAST(CDialog, CWnd:FromHandlePermanent(hWnd);if (pDlg != NULL)return pDlg->OnInitDialog();elsereturn 1;return 0;由上可以看出,MFC的对话框函数AfxDlgProc仅处理消息WM_INITDIALOG,其他都留给对话框窗口过程处理。因此,它不同于SDK编程的对话框过程。程序员在SDK的对话框过程处理消息和事件,实现自己的对话框功能。AfxDlgProc处理WM_INITDIAL

27、OG消息时调用虚拟函数OnInitDialog,给程序员一个机会处理对话框的初始化第4章 调试分析4.1 实际完成的情况说明(完成的功能,支持的数据类型等)。 本程序着力于局域网内文字聊天功能的实现,根据局域网内IP地址的不同,实现数据通信,本程序支持数字,简单文字数据,对图片,视频等多媒体信息暂不支持,对简单文字聊天的实现一般局限在200个字符以内的,这是发送窗口,接收窗口一般可以接受300个字符左右 程序功能的实现: 在对方IP栏输入本局域网内对方主机的IP,然后在发送数据窗口输入聊天内容,点击发送或按Enter键即可完成消息的发送,但前提是双方主机都有运行本程序4.2程序的性能分析。 本

28、程序实现了简单的局域网聊天功能,利用基于网络通信的UDP/IP协议,不需要先建立连接,使服务器端和客户端基于一个对话框上,实现起来比较简单,利用独立的协议端口号使得通信变得可能,占用内存较小其性能对于完成的功能来说是比较优越,时间利用率还是很高的。4.3 上机过程中出现的问题及其解决方案。1、 套接字调用错误 本程序使用套接字技术,首先要对套接字库的版本进行协商,利用的是AfxSocketInit()函数,调用此函数首先要声明其头文件#include<Afxsock.h>2、套接字的绑定总是成功的(没有错误提示),但是发送信息总是失败。 在代码书写过程中:int retval;bi

29、nd (m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR); if(SOCKET_ERROR=retval)closesocket(m_socket);MessageBox("绑定失败!");return FALSE;错误;使得if(SOCKET_ERROR=retval)总是FALSE,原因在于bind返回值的错误,应该为retval= bind (m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR);3、 套接字总是提示“绑定失败!”发现代码无误,在宿舍自己电脑上绑定成功,

30、而在机房电脑上某个主机可以成功,某些失败,经分析可能是bind的绑定IP/端口问题,通过更改端口号6000(开始设置的端口号)->6020(更改后的端口号),在经过测试,程序无误。4、 DWORD WINAPI RecvProc(LPVOID lpParameter); 当我们创建一个线程的时候系统会调用一个线程函数从而启用这个线程,而这个函数是CChatDlg的成员函数,那我们必须先定义一个CChatDlg对象再调用函数,线程函数调用是不需要对象的,所以产生了错误 我们可以通过创建一个静态的函数,那么它不属于哪个对象,它属于这个类,当我们在创建线程后就可以直接调用这个函数。5、 主机字

31、节序向网络字节序的转化问题当我们按下发送键时根据IP地址发送数据,那么我们首先要得到一个IP地址就要用到CIPAddressCtrl类,其中有一个函数GetAddress用来获取主机IP:(CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1)->GetAddress(dwIP);/主机IP字节序就这里 我们该如何利用这个IP地址来收发数据:要定义一个地址结构体的变量SOCKADDR_IN addrTo;问题在于下面:如何在局域网内实现,就要转化成网络的IP字节序:addrTo.sin_addr.S_un.S_addr=htonl(dwIP);/转化成网络的

32、字节序6、 IP地址转化(点分十进制)用函数inet_ntoa(addrFrom.sin_addr)7、 接收数据窗口实现数据传递:PostMessage();BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ); 4.4 程序中可以改进的地方说明。1、 接收窗口数据要包括原有数据2、 对话框界面很简洁,可以美化一下3、 为了聊天的方便可以隐藏发送按钮,直接按Enter发送消息4、 接收窗口如果包括发送的消息那样更有利于聊天5、 Udp数据通信是不可靠的通信,那么如果改为tcp可以保证数据通信的正确完成6、 程

33、序中还可以加入一些辅助的功能,例如 在对话框界面加入一个和关闭按钮或是取消按钮等等4.5 程序中可以扩充的功能及设计实现构想。1、接收窗口数据要不仅要有发送的数据还要包括原有数据:CString str1=(char*)lParam;CString strTemp;GetDlgItemText(IDC_EDIT_RECV,strTemp);str1+="rn"str1+=strTemp;SetDlgItemText(IDC_EDIT_RECV,str1); 2、 在聊天过程中,能否把自己发送的数据和对方发来的数据都显示在自己程序的接收窗口上:void CChatDlg:On

34、RecvData(WPARAM wParam,LPARAM lParam) CString str=(char*)lParam;CString str0=(char*)lParam; CString strTemp; GetDlgItemText(IDC_EDIT_RECV,strTemp); GetDlgItemText(IDC_EDIT_SEND,str0); str+="rn" str+=strTemp; SetDlgItemText(IDC_EDIT_RECV,str+str0);3、 为了聊天的方便可以隐藏发送按钮,直接按Enter发送消息在资源.rc文件中把发送

35、按钮的属性改为不可见和default属性即可。4、 在聊天窗口界面加入一些附加功能,例如一个取消按钮:void CDialog:OnCancel() EndDialog(IDCANCEL); 这就是退出操作,你可以发送WM_CLOSE消息第5章 用户手册说明程序的运行环境,程序执行结果,详细列出每一步的操作步骤。(可以插入图)本程序意在解决局域网内文字聊天的问题,利用VC+中的MFC实现,程序操作起来比较简单,一般步骤如下:(前提是局域网内的主机上都有运行本程序)1) 运行该程序2) 在对方IP一栏输入本局域网内进行聊天的主机IP3) 发送窗口即输入进行聊天的文本信息4) 按发送即可完成本次聊

36、天信息的实现5) 接收窗口用来接收来自本局域网内的聊天信息6) 完毕(此截图基于本地回路地址发送数据)(局域网内的聊天实现)第6章 设计总结在 12 月 21 日拿到 C+课程设计的题目时,脑子一下子懵了,看到每个题目都有一定的 难度,最难的就是使用 MFC 在 VC 的平台下做出可视化的程序来。当时,对于可视化编程还 没有基本的概念,对于能编出可视化的程序更没有指望了,自己当时不知所措,更无从下手 了。不过,我们班有几个同学已经有了一定的 MFC 编程基础,据他们的经验,最初步进行学 习的时候是通过看孙鑫讲解的 VC 编程视频和看一下网上程序,初步对 MFC 进行了解。然后再接下来的三天里自己开始观看孙鑫老师的视频教程。主要是了解了 MFC 下的编 程,了解了 MFC 编程主要是通过定义 MFC 类的对象并通过调用对象的函数来实现相应的功能。 在有了对于 MFC 的了解后,我从题目中选择了局域网聊天程序设计这个题目,我认

温馨提示

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

评论

0/150

提交评论