1、基于UDP协议的网上聊天程序 湖南工业大学课 程 设 计资 料 袋 计算机与通信学院 学院(系、部) 2011 2012 学年第 1 学期 课程名称 计算机网络原理 指导教师 李建设 职称 副教授 学生姓名 蒋政 专业班级 软件092 学号 09408300209 题 目 基于UDP协议网上聊天程序 成 绩 起止日期 2011 年 11 月 24 日 2011 年 12 月 4 日目 录 清 单序号材 料 名 称资料数量备 注1课程设计任务书2课程设计说明书3456课程设计任务书2010 2011学年第 2 学期学院(系、部) 计算机与通信学院 专业 软件工程 班级 091-3 课程名称: 计
2、算机网络原理 学生姓名: 蒋政 设计题目: 基于UDP协议网上聊天程序 指导教师: 李建设 完成期限:自 2011 年 11 月 24 日至 2011 年 12 月 4 日 共 2 周内容及任务一、设计内容实现一简单的聊天程序实现网上聊天,包括服务器和客户端。1. 支持多人聊天。2. 客户端具有图形化用户界面。二、设计任务课程设计说明书(纸质+电子版),内容包括:设计内容、系统分析(包括可行性分析、需求分析等)及功能分析;系统设计(要求画出系统整体功能框图、流程图、并给出相应地关键的代码且对所使用的主要数据结构进行说明等。)、设计总结(评价/遇到的问题/体会/建议等)、使用说明等。三、设计要求
3、1. 按功能要求开发系统,能正确运行。程序代码书写规范,有充足的注释。2. 课程设计所使用的编程语言任选,但建议使用C或C+;3. 绿色软件:程序运行不需安装,避免写系统和注册表;进度安排起止日期工作内容2011-11-242011-11-27选题2011-11-282011-11-29系统分析和设计;2011-11-302011-12-3熟悉软件开发工具、编码系统、系统测试2011-12-042011-12-05撰写并提交课程设计说明书 (含电子文档)、源程序等。主要参考资料1 (美) Larry Peterson著,薛静锋等译. 计算机网络:系统方法 (第4版) ,机械工业出版社,2009
4、2 (荷) Andrew S.Tanenbaum著,潘爱民译. 计算机网络(第4版),清华大学出版社, 20043 谢希仁著.计算机网络(第5版) ,电子工业出版社, 2008.14 吴功宜等著.计算机网络课程设计,机械工业出版社,2005指导教师(签字): 年 月 日系(教研室)主任(签字): 年 月 日课程设计说明书 课程名称: 计算机网络原理 设计题目: 基于UDP协议的聊天程序 专 业: 软件工程 班级: 092 学生姓名: 蒋政 学 号: 09408300209 指导教师: 李建设 年 月 日 目录 1. 课程设计具体实现过程. 4 2. 具体代码的实现 8 3.注意事项. 124.
5、参考文献. 12 一 . 多线程编程聊天程序的具体实现1 创建MFC-EXE 工程,工程名为 Chat,Dialog based。2 删除对话框控件,添加自己的控件,各个控件的ID分别为:接受文本框的ID为IDC_EDIT_RECV,发送数据的文本框ID为IDC_EDIT_SEND,发送按钮的ID为IDC_BTN_SEND。其余默认即可。3 加载套接字库,进行版本协商MFC环境下使用 AfxSocketInit(查看MSDN帮助)AfxSocketInit加载的1.1版本,可以确保Socket库的释放MSDN中提到在 CWinApp:InitInstance中使用在这里就是 CChatAPP类
6、的InitInstance中调用 if(!AfxSocketInit() AfxMessageBox(加载套接字库失败!); return FALSE; 4 刚才使用了 AfxSocketInit 需要加入头文件#include 放入到 StdAfx.h的头文件中,StdAfx.h是预编译头文件,包括MFC工程必要的头文件5 在CChatDlg类中定义一个成员函数,作为套接字初始化工作 BOOL InitSocket()同时增加一个 变量 SOCKET m_socket6 实现 InitSocket() m_socket=socket(AF_INET,SOCK_DGRAM,0); if(INV
7、ALID_SOCKET=m_socket) MessageBox(套接字创建失败!); return FALSE; SOCKADDR_IN addrSock; addrSock.sin_family=AF_INET; addrSock.sin_port=htons(1234);addrSock.sin_addr.S_un.S_addr=inet_addr(127.0.0.1); int retval; retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR); int retv = WSAGetLastError(); if(SOCK
8、ET_ERROR=retval) closesocket(m_socket); MessageBox(绑定失败!); return FALSE; return TRUE;7 在CChatDlg的OnInitDialog()的最后调用InitSocket()8 下面编写接收端程序(1)当接受数据时如果没有数据到来,recvfrom函数会阻塞,从而导致进程暂停运行,所以采用线程来完成 (2)创建线程后,我们需要传递两个参数,一个是套接字,一个是对话框的句柄(接受编辑框的句柄),这样可以通过套接字接受数据,传给接受编辑框,但CreateThread只能传递一个参数(第四个),但是个指针9 在 CCh
9、atDlg的头文件中 定义一个结构体struct RECVPARAM SOCKET sock; HWND hwnd; /注意这里的分号10 在CChatDlg的OnInitDialog()最后,即InitSocket()后 RECVPARAM *pRecvParam=new RECVPARAM; pRecvParam-sock=m_socket; pRecvParam-hwnd=m_hWnd; HANDLE hThread=CreateThread (NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL); CloseHandle(hThread); return
10、 TRUE;11 加入线程函数,从MSDN中COPY加入一个全局函数,有的单位要求不允许使用全局函数,那这里加给 CChatDlg类,作为一个成员函数DWORD WINAPI RecvProc (LPVOID lpParameter)12此时程序报错,因为要执行 RecvProc 需要CChatDlg的实例,不能在类中调用,所以报错解决方法:在CChatDlg头文件中,将RecvProc函数定义为static类型13 实现线程函数 SOCKET sock=(RECVPARAM*)lpParameter)-sock; HWND hwnd=(RECVPARAM*)lpParameter)-hwnd
11、; delete lpParameter; SOCKADDR_IN addrFrom; int len=sizeof(SOCKADDR); char recvBuf200; char tempBuf300; int retval; while(TRUE) retval=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len); if(SOCKET_ERROR=retval) break; sprintf(tempBuf,%s说: %s,inet_ntoa(addrFrom.sin_addr),recvBuf); :PostMessage(hw
12、nd,WM_RECVDATA,0,(LPARAM)tempBuf); /发送数据 传送一个自定义消息,传给窗口 return 0;14 加入消息相应机制(1)在CChatDlg的头文件中 定义消息值,加入#define WM_RECVDATA WM_USER+1(2)做一个消息相应函数原型的声明在CChatDlg的头文件的下方的 protected声明中加入afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam); /注意加入了两个参数,因为PostMessage发送消息的过程中传递了参数(3)加入消息映射:注意因为CAboutDlg类和CCha
13、tDlg类在一个CPP文件中,所以消息映射一定要加正确了找到 BEGIN_MESSAGE_MAP(CChatDlg, CDialog)在最后面写入: ON_MESSAGE(WM_RECVDATA,OnRecvData)第一个参数是 消息本身:WM_RECVDATA第二个参数是 消息相应函数:OnRecvData注意后面不要加分号(4)最后是消息相应函数的实现在 CPP最后加入void CChatDlg:OnRecvData(WPARAM wParam,LPARAM lParam)15实现刚才加入的 OnRecvData 消息相应函数 CString str=(char*)lParam; CSt
14、ring strTemp;/获取旧文本 GetDlgItemText(IDC_EDIT_RECV,strTemp); str+=rn; /增加一个换行 str+=strTemp; SetDlgItemText(IDC_EDIT_RECV,str);/放到编辑框16双击发送按钮,系统自动生成按钮相应事件(1) 首先要获取IP,查看MSDN帮助CIPAddressCtrlCIPAddressCtrl对应的就是IP控件,通过一个DWORD类型的变量来接受IP地址首先得到控件的指针:GetDlgItem(IDC_IPADDRESS1)强制转换为 (CIPAddressCtrl*)类型最后调用CIPAd
15、dressCtrl下的一个函数GetAddress完整的程序是 DWORD dwIP; ( (CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1) )-GetAddress(dwIP);(2) 得到IP地址后,可以发送数据,继续在后面加入代码 SOCKADDR_IN addrTo; addrTo.sin_family=AF_INET; addrTo.sin_port=htons(1234); addrTo.sin_addr.S_un.S_addr=htonl(dwIP); CString strSend; GetDlgItemText(IDC_EDIT_SEND
16、,strSend); sendto(m_socket,strSend , strSend.GetLength()+1,0, (SOCKADDR*)&addrTo,sizeof(SOCKADDR); SetDlgItemText(IDC_EDIT_SEND,);17 此时发现 文本框并没有 换行显示选择 接收数据的文本框控件,右键选择属性,在Styles中选择 Multiline就可以了;18 为了让我们回车就发送数据,可以设置发送按钮为缺省按钮,可以右键选择按钮属性,在在Styles中选择 Default button就可以了。 二 . 具体代码的实现 CPaintDC dc(this); /
17、 device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); / Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Hei
18、ght() - cyIcon + 1) / 2; / Draw the icon dc.DrawIcon(x, y, m_hIcon); else CDialog:OnPaint(); / The system calls this to obtain the cursor to display while the user drags/ the minimized window.HCURSOR CChartDlg:OnQueryDragIcon() return (HCURSOR) m_hIcon;BOOL CChartDlg:InitSocket() m_socket=socket(AF_
19、INET,SOCK_DGRAM,0); if(INVALID_SOCKET=m_socket) MessageBox(套接字创建失败!); return FALSE; SOCKADDR_IN addrSock; addrSock.sin_family=AF_INET; addrSock.sin_port=htons(1234); addrSock.sin_addr.S_un.S_addr=inet_addr(GethostIP(); int retval; retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR); int retv
20、= WSAGetLastError(); if(SOCKET_ERROR=retval) closesocket(m_socket); MessageBox(绑定失败!); return FALSE; return TRUE;DWORD WINAPI CChartDlg:RecvProc(LPVOID lpParameter) SOCKET sock=(RECVPARAM*)lpParameter)-sock; HWND hwnd=(RECVPARAM*)lpParameter)-hwnd; delete lpParameter; SOCKADDR_IN addrFrom; int len=s
21、izeof(SOCKADDR); char recvBuf200; char tempBuf300; int retval; while(TRUE) retval=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len); if(SOCKET_ERROR=retval) break; sprintf(tempBuf,%s说: %s,inet_ntoa(addrFrom.sin_addr),recvBuf); :PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf); /发送数据 传送一个自定义消息,传给
22、窗口 return 0;void CChartDlg:OnRecvData(WPARAM wParam,LPARAM lParam) CString str=(char*)lParam; CString strTemp; /获取旧文本 GetDlgItemText(IDC_EDIT_RECV,strTemp); if(strTemp!=)strTemp+=rn; /增加一个换行 strTemp+=str; SetDlgItemText(IDC_EDIT_RECV,strTemp); (CEdit*)GetDlgItem(IDC_EDIT_RECV)-LineScroll(CEdit*)GetD
23、lgItem(IDC_EDIT_RECV)-GetLineCount();void CChartDlg:OnButtonSend() / TODO: Add your control notification handler code here DWORD dwIP; ( (CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1) )-GetAddress(dwIP); SOCKADDR_IN addrTo; addrTo.sin_family=AF_INET; addrTo.sin_port=htons(1234); addrTo.sin_addr.S_un.S_
24、addr=htonl(dwIP); CString strSend; GetDlgItemText(IDC_EDIT_SEND,strSend); sendto(m_socket,strSend , strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR); SetDlgItemText(IDC_EDIT_SEND,); CString strTemp; CString str=我说:+strSend; /获取旧文本 GetDlgItemText(IDC_EDIT_RECV,strTemp); if(strTemp!=)strTem
25、p+=rn; /增加一个换行 strTemp+=str; SetDlgItemText(IDC_EDIT_RECV,strTemp); (CEdit*)GetDlgItem(IDC_EDIT_RECV)-LineScroll(CEdit*)GetDlgItem(IDC_EDIT_RECV)-GetLineCount();LPCSTR CChartDlg:GethostIP() char name255; PHOSTENT hostinfo; LPCSTR ip; if(gethostname(name,sizeof(name)=0) /如果能获取计算机主机信息的话,则获取本机IP地址 if(h
26、ostinfo=gethostbyname(name)!=NULL) ip=inet_ntoa(*(struct in_addr*)*hostinfo-h_addr_list); return ip;三 . 注意事项:1 一定要保证 bind的端口和recvfrom的端口号一致;2 在绑定的IP地址设置中,如果只与本地进行通信,采用(127.0.0.1) 是可以的,但如果和其他网络的机器进行通信,必须写完整的机器IP,比如:(172.18.49.126);3 注意控件的ID要一致,比如这里的示例中:接受文本框的ID为IDC_EDIT_RECV,发送数据的文本框ID为IDC_EDIT_SEND,发送按钮的ID为IDC_BT。四 . 参考文献1 袁庆龙,候文义Ni-P合金镀层组织形貌及显微硬度研究太原理工大学学报,2001,32(1):51-53.(连续出版物:序号 主要责任者文献题名J刊名,出版年份,卷号(期号):起止页码)2刘国钧,王连成图书馆史研究北京:高等教育出版社,1979:15-18,31(专著:序号 主要责任者文献题名出版地:出版者,出版年:起止页码)3 孙品一高校学报编辑工作现代化特征中国高等学校自然科学学报研究会科技编辑学论文集(2)北京:北京师范大学出版社,1998:10-22(论文集:序号 主要责任者文献题名主编论文集名出版地:出版者,出版年:起止页码)
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1