赵凯可视化程序设计考查作业-编写一个网络聊天软件_第1页
赵凯可视化程序设计考查作业-编写一个网络聊天软件_第2页
赵凯可视化程序设计考查作业-编写一个网络聊天软件_第3页
赵凯可视化程序设计考查作业-编写一个网络聊天软件_第4页
赵凯可视化程序设计考查作业-编写一个网络聊天软件_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

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

文档简介

1、目录一、设计分析2二、需求分析2三、程序结构3四、源程序4五、操作方法及结果10六、实验结果11七、设计体会12一、设计分析1、该程序实现局域网内的聊天功能,包括服务器端程序和客户端程序两部分。客户端程序:可连接到服务器,并将消息发送到服务器端和接受服务器端发送到的消息。服务器端程序:负责发送用户列表和转发客户端发送过来的消息。本程序涉及到服务器端和客户端,采用同一个套接字。2、该聊天软件是采用UDP连接,UDP是OSI参考模型中一种无连接的传输层协议,它提供了简单不可靠的信息传送服务。由于UDP比较简单,UDP包含很少的字节,所以它在速度方面有很大优势。很多常用的即时通软件,如QQ程序,都会

2、使用UDP实现很多基本功能。UDP是“面向非连接”的网络协议,它与“面向连接”的TCP协议对应。在发送数据之前,并不与对方建立连接,而是直接把数据报发出去,不保证可靠的传输。UDP相对TCP简单,在速度方面有很大优势,因为它的网络开销少,对传输可靠性要求不是很高的情况下,UDP的使用是网络程序的首选。3、要实现聊天功能必须获取两台计算机的IP地。在IP地址控件栏输入参与聊天对象的计算机的IP地址。4、本程序的核心在于将消息的发送的和接收发在了两个不同的线程中,接收放在新创建的副进程中,因为其要一直处于响应状态,也就是需要一个while循环;发送放在主线程中。这样消息的接收和发送就不存在先后顺序

3、了,且一直处于循环中的接收也不会影响到发送。5、程序代码中的新线程入口函数中可能没有必要传递两个参数进去,其中SOCKET参数可以在入口函数内部创建, SOCKET变量也就是声明是TCP还是UDP,和发送或接收没有必然的联系,如果这样的话,就没有必要声明“详细设计”第五步中的结构体了,CreateThread方法也刚好传递一个参数,即当前窗口的句柄。二、需求分析1、在VC+6.0中MFC中创建新文档,选中基本对话框栏,然后进行对话框的设置,选择不同的控件,分别设置接收数据、发送数据和发送的控件。2、对需要用的变量进行定义并初始化等。3、实现不同的功能响应不同的消息处理函数,实现套接字绑定获取I

4、P地址等功能。4、理解CWinApp中的InitInstance函数的用法及功能。5、WSACleanup函数的调用与终止等。6、各种不同代码的功能与实现原理。三、程序结构1、对需要用的变量进行定义或申明。2、调用相应的MFC内置函数,对相应的变量进行初始化等操作。3、程序设计的概要流程图如下:开始编辑界面添加套接字库头文件,调用WSACleanup ,包含头文件Afxsock.h调用MFC的内置函数 AfxSocketInit,创建套接字在CDialog中添加成员变量:SOCKET m_socket,和自定义函数:BOOL CChatDlg:InitSocket(),加载套接字库在CChat

5、Dlg类添加代码分别完成服务器的创建和客户端消息的传送定义自定义消息的宏:#define WM_RECVDATA WM_USER+1,完成消息的接收和显示部分在发送按钮点击的响应函数中添加相应函数代码结束 图1 程序设计流程图四、源程序1、创建一个基于对话框的MFC程序设计,界面如下: 图2 对话框界面2、添加套接字库头文件:函数能准确保证程序终止前调用WSACleanup的调用,该函数其实也是调用Win32中的WSAStartup,该函数的调用位置最好在CWinApp中的InitInstance中,包含头文件Afxsock.h,在StdAfx.h这个头文件中调用MFC的内置函数AfxSock

6、etInit,该函数其他也是调用Win32中的WSASAtartup,该进行包含。StdAfx.h头文件是一个预编译头文件,在该文件中包含了MFC程序运行的一些必要的头文件,如afxwin.h这样的MFC核心头文件等。一些必要的头文件,如afxwin.h这样的MFC核心头文件等。它是一个被程序加载的文件。3、加载套接字库:在CWinApp中的InitInstance添加如下代码:if(FALSE=AfxSocketInit()              &

7、#160;  AfxMessageBox("套接字库加载失败!");           return FALSE;4、创建套接字:将自己假想成服务器端,进行套接字和地址结构的绑定,等待别人发送消息过来。在CDialog中添加成员变量:SOCKET m_socket添加自定义函数:BOOL CChatDlg:InitSocket()    m_socket=socket(AF_INET,SOCK_DGRAM

8、,0); /UDP连接方式      if(INVALID_SOCKET=m_socket)                 MessageBox("套接字创建失败!");           return FALSE; 

9、;           SOCKADDR_IN addrServer; /将自己假想成server      addrServer.sin_addr.S_un.S_addr=htonl(INADDR_ANY);      addrServer.sin_family=AF_INET;      add

10、rServer.sin_port=htons(1234);      int retVal;      retVal=bind(addrSock,(SOCKADDR*)&addrServer,sizeof(SOCKADDR);      if(SOCKET_ERROR=retVal)          

11、;       closesocket(addrSock);           MessageBox("套接字绑定失败!");           return FALSE;        

12、0;   return TRUE;5、在CChatDlg类的外部添加结构体:struct RECVPARAM    SOCKET sock; /保存最初创建的套接字    HWND hWnd; /保存对话框的窗口句柄;6、在对话框的初始化代码中完成线程的创建:在CChatDlg:OnInitDialog函数中添加下面的代码:if(!InitSocket() /服务器端的创建      return 

13、;FALSE;      RECVPARAM *pRecvParam=new RECVPARAM;      pRecvParam->hWnd=m_hWnd;      pRecvParam->sock=m_socket; 说明:1)接收部分应该一直处于响应状态,如果和发送部分放在同一段代码中,势必会阻塞掉发送功能的实现,所以考虑将接收放在单独的线程中,使它在一个while循环中,始终处于响应状

14、态2)因为需要传递两个参数进去,一个是recvfrom需要用的套接字,另一个是当收到数据后需要将数据显示在窗口中的对应文本框控件上,所以需要传递当前窗口的句柄,但CreateThread方法只能传递一个参数,即第四个参数,这时候就想到了采用结构体的方式传递。HANDLE hThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);CloseHandle(hThread); 7、创建线程入口函数RecvProc:如果是成员函数的话,那它属于某个具体的对象,那么在调用它的时候势必要让程序创建一个对象,但该对象的构造函数有

15、参数的话,系统就不知所措了,所以可以将函数创建为全局函数,即不属于类,但这失去了类的封装性,最好的方法是将该方法声明为静态方法,它不属于任何一个对象。在CChatDlg类的头文件中添加:static DWORD WINAPI RecvProc(LPVOID lpParameter);在cpp文件中添加:DWORD WINAPI CChatDlg:RecvProc(LPVOID lpParameter)      RECVPARAM* pRecvParam=(RECVPARAM*)lpParameter;  

16、;    HWND hWnd=pRecvParam->hWnd;      SOCKET sock=pRecvParam->sock;      char recvBuf200;      char resultBuf200;      SOCKADDR_IN addrFrom;

17、0;/这个时候是假想成服务器端      int len=sizeof(SOCKADDR_IN);      while(TRUE) /处于持续响应状态               int retVal=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,

18、&len);           if(SOCKET_ERROR = retVal)           AfxMessageBox("接收数据出错");break;                  

19、  else          sprintf(resultBuf,"%ssaid:%s",inet_ntoa(addFrom.sin_addr),recvBuf); /现在已经拿到客户端送过来的消息了,但因为自身是静态函数,所以拿不到当前窗口对象中的控件的句柄,也就不能对其赋值了,唯一办法就是用消息的形式将接收到的值抛出到窗口的消息队列中,等待消息处理           :

20、PostMessage(hWnd,WM_RECVDATA,0,(LPARAM)resultBuf);                     return 0;8、自定义消息:定义自定义消息的宏:#define WM_RECVDATA WM_USER+1声明消息响应函数:因为有参数要传递,所以wParam和lParam都要写,如果没有 要传递,可以不写afx_msg void 

21、OnRecvData(WPARAM wParam,LPARAM lParam);消息映射:ON_MESSAGE(WM_RECVDATA,OnRecvData)定义消息响应函数:void CChatDlg:OnRecvData(WPARAM wParam,LPARAM lParam)      CString recvData=(char*)lParam;      CString temp;      &#

22、160;GetDlgItemText(IDC_EDIT_RECV,temp);      temp+="rn"      temp+=recvData;      SetDlgItemText(IDC_EDIT_RECV,temp);自此,消息的接收和显示部分已经完成了 9、消息的发送:在发送按钮点击的响应函数中添加:    DWORD dword

23、;    CIPAddressCtrl* pIPAddr=(CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1);    pIPAddr->GetAddress(dword);  /因为对方有具体的IP地址值,我们假想对方是服务器端。在发送的时候程序就从服务器的角色转变为客户端了    SOCKADDR_IN addrServer;    addrServer.sin_addr.S_un.

24、S_addr=htonl(dword);    addrServer.sin_family=AF_INET;    addrServer.sin_port=htons(1234);    CString strSend;    GetDlgItemText(IDC_EDIT_SEND,strSend);    sendto(m_socket,strSend,strlen(strSend)+1,0,(SOCKADDR*)&addrServer,sizeof(SOCKADDR);SetDlgItemText(IDC_EDIT_SEND,"");10、消息面版的控制:至此,整个聊天软件的程序设计已经完成,但当你运行的时候发现两次发送的消息会在同一行出现。如图所示:此时,需要鼠标选中接收数据中的编辑一栏,更改其属性,选中属性中的样式然后选中多行。整个聊天软件的是设计与实现已经完成。五、操作方法及结果1、测试数据(如下图所示): 图3 测

温馨提示

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

评论

0/150

提交评论