-1-23青岛理工大学C++面向对象课程设计报告院(系):计算机工程学院专业:计算机科学与技术学生姓名:张义华班级:__113___学号:201107104题目:局域网聊天程序起迄日期:_2013.6.23~2013.7.5设计地点:计算机学院机房指导教师:李兰完成日期:2013年7月5-2-23目录一、需求分析-----------------------------------------------------------------------------------------------31.1客户端1.2服务端二、设计内容-----------------------------------------------------------------------------------------------42.1程序整体构建逻辑图2.2基于UDP的客户端和服务端的连接逻辑图2.3各模块代码实现三、调试分析-----------------------------------------------------------------------------------------------103.1实际完成的情况说明3.2程序的性能分析和上机过程中出现的问题及其解决方案3.3程序中可以改进的地方说明四、用户手册-----------------------------------------------------------------------------------------------11五、设计总结-----------------------------------------------------------------------------------------------13六、参考文献-----------------------------------------------------------------------------------------------13七、附录-----------------------------------------------------------------------------------------------------14-3-23一、需求分析这次开发的局域网聊天工具目标在于在局域网环境下能够简单的实现人与人的即时通讯,要求收发信息速度快、安全性高和精准性高。本软件基于visualc++6.0环境下开发,并采用MFC进行处理,界面具有基本的功能按钮,于此本人还添加了一个查询本地的主机名和IP地址的功能。同时,本软件包含有客户端和服务端,他们之间是基于UDP协议下进行通信的,他们具备的功能如下:1.1客户端①点击查询按钮获取本地主机名和IP②获取远程服务端端口③输入远程服务端IP并连接④用户能够自定义编辑发送信息并点击发送按钮发送⑤用户能够接收到来自远程服务端的信息⑥用户右键点击窗口可以查询软件版本⑦自动建立一个文件存储聊天记录1.2服务端①点击查询按钮获取本地主机名和IP②获取远程客户端端口③输入远程客户端IP并连接④用户能够自定义编辑发送信息并点击发送按钮发送⑤用户能够接收到来自远程客户端的信息⑥用户右键点击窗口可以查询软件版本⑦自动建立一个文件存储聊天记录-4-23二、设计内容2.1程序整体构建逻辑图:按需求建立对话框在CCHATDlg类中添加新成员函数添加RECVPARAM结构体structRECVPARAM{SOCKETsock;HWNDhwnd;};InitSocket()RecvProc(LPVOIDIpParameter)OnBUTTONsearch()OnBtnSend()OnRecvData(WPARAMwParam,,LPARAMIParam)Record(CStringrecordString)实现各成员函数初始化套接字消息处理函数查询本地主机名和IP发送消息接收消息聊天记录函数-5-232.2基于UDP的客户端和服务端的连接逻辑图基于UDP的套接字编程,对于接收端(服务端)来说,它必须先启动以接收客户端发送的数据,因此接收端必须告诉主机它是在哪个地址和端口上等待数据的到来,也就是说,接收端(服务端)必须调用bind()函数将套接字绑定到一个本地地址和端口上。Socket()服务端Bind()recvfrom()Close()Socket()客户端Sendto()Recvfrom()Close()Sendto()-6-232.3各模块代码实现1)、//初始化套接字BOOLCCHATDlg::InitSocket(){m_socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);if(m_socket==INVALID_SOCKET){MessageBox(套接字创建失败!);returnFALSE;}SOCKADDR_INServerAddr;ServerAddr.sin_family=AF_INET;ServerAddr.sin_port=htons(6000);ServerAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);intretval;retval=bind(m_socket,(SOCKADDR*)&ServerAddr,sizeof(SOCKADDR));if(retval==SOCKET_ERROR){closesocket(m_socket);MessageBox(绑定失败!);returnFALSE;}returnTRUE;}2)、//消息处理函数,注意在声明时应该为staticDWORDWINAPICCHATDlg::RecvProc(LPVOIDlpParameter){SOCKETsock=((RECVPARAM*)lpParameter)-sock;HWNDhwnd=((RECVPARAM*)lpParameter)-hwnd;SOCKADDR_INClientAddr;intlen=sizeof(SOCKADDR);charrecvBuf[512];chartempBuf[512];intretval;-7-23while(1){retval=recvfrom(sock,recvBuf,512,0,(SOCKADDR*)&ClientAddr,&len);if(retval==SOCKET_ERROR)break;sprintf(tempBuf,(%s):%s,inet_ntoa(ClientAddr.sin_addr),recvBuf);::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);}return0;}3)、同时,在BOOLCCHATDlg::OnInitDialog()添加如下代码:InitSocket();//套接字初始化RECVPARAM*pRecvParam=newRECVPARAM;pRecvParam-sock=m_socket;pRecvParam-hwnd=m_hWnd;HANDLEhThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);CloseHandle(hThread);4)、定义一个全局静态变量CStringNewString用于进行格式输出和记录聊天消息//发送数据voidCCHATDlg::OnBtnSend(){//TODO:AddyourcontrolnotificationhandlercodeherDWORDdwIP;((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))-GetAddress(dwIP);SOCKADDR_INClientAddr;ClientAddr.sin_family=AF_INET;ClientAddr.sin_port=htons(5150);ClientAddr.sin_addr.S_un.S_addr=htonl(dwIP);CStringstrSend;CStringstrTime;GetDlgItemText(IDC_EDIT_SEND,strSend);if(strSend.GetLength()==0)-8-23{MessageBox(发送的消息不能为空!);}else{sendto(m_socket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&ClientAddr,sizeof(SOCKADDR));SetDlgItemText(IDC_EDIT_SEND,);//聊天消息时间记录CTimetm;tm=CTime::GetCurrentTime();strTime=tm.Format(%Y-%m-%d%X);strSend=strSend+【;strSend+=strTime;strSend=strSend+】;strSend+=\r\n;NewString+=\r\n;NewString+=我:;NewString+=strSend;Record(NewString);//调用消息记录函数SetDlgItemText(IDC_EDIT_RECV,NewString);//回显在本地聊天窗口}}5)、//接收数据voidCCHATDlg::OnRecvData(WPARAMwParam,LPARAMlParam){CStringstr=(char*)lParam;CStringstrTime;GetDlgItemText(IDC_EDIT_RECV,NewString);//聊天消息时间记录CTimetm;tm=CTime::GetCurrentTime();-9-23strTime=tm.Format(%Y-%m-%d%X);str=str+【;str+=strTime;str=str+】;str+=\r\n;NewString+=\r\n;NewString+=str;SetDlgItemText(IDC_EDIT_RECV,NewString);Record(NewString);//调用消息记录函数}6)、附加查询本地主机名和IP功能voidCCHATDlg::OnBUTTONsearch()//查询按钮{WSADATAwsaData;WSAStartup(MAKEWORD(1,1),&wsaData);charszHostName[128];if(gethostname(szHostName,128)==0)//获取主机名{m_HostName.SetWindowText(szHostName);hostent*ent=gethostbyname(szHostName);//获取主机信息for(inti=0;ent!=NULL&&ent-h_addr_list[i]!=NULL;i++){LPCTSTRIpAddr=inet_ntoa(*(in_addr*)ent-h_addr_list[i]);//转换成点分十进制格式m_IPAddr.AddString(IpAddr);}}WSACleanup();}-10-237)、聊天记录intCCHATDlg::Record(CStringrecordString)//消息记录函数{CFilerecordFile(TheRecords.txt,CFile::modeCreate|CFile::modeWrite);//定义文件对象recordFile.Write(recordString,strlen(recordString));recordFile.Close();return0;}8)、在CHATDlg.h文件添加宏:#defineWM_RECVDATAWM_USER+1三、调试分析1、实际完成的情况说明:本软件目前完成了