基于UDP协议的网上聊天程序.docx

上传人:b****5 文档编号:30758921 上传时间:2023-08-20 格式:DOCX 页数:16 大小:35.69KB
下载 相关 举报
基于UDP协议的网上聊天程序.docx_第1页
第1页 / 共16页
基于UDP协议的网上聊天程序.docx_第2页
第2页 / 共16页
基于UDP协议的网上聊天程序.docx_第3页
第3页 / 共16页
基于UDP协议的网上聊天程序.docx_第4页
第4页 / 共16页
基于UDP协议的网上聊天程序.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

基于UDP协议的网上聊天程序.docx

《基于UDP协议的网上聊天程序.docx》由会员分享,可在线阅读,更多相关《基于UDP协议的网上聊天程序.docx(16页珍藏版)》请在冰豆网上搜索。

基于UDP协议的网上聊天程序.docx

基于UDP协议的网上聊天程序

湖南工业大学

课程设计

资料袋

计算机与通信学院学院(系、部)2011~2012学年第1学期

课程名称计算机网络原理指导教师李建设职称副教授

学生姓名蒋政专业班级软件092学号09408300209

题目基于UDP协议网上聊天程序

成绩起止日期2011年11月24日~2011年12月4日

目录清单

序号

材料名称

资料数量

备注

1

课程设计任务书

2

课程设计说明书

3

4

5

6

课程设计任务书

2010—2011学年第2学期

学院(系、部)计算机与通信学院专业软件工程班级091-3

课程名称:

计算机网络原理学生姓名:

蒋政

设计题目:

基于UDP协议网上聊天程序指导教师:

李建设

完成期限:

自2011年11月24日至2011年12月4日共2周

一、设计内容

实现一简单的聊天程序实现网上聊天,包括服务器和客户端。

1.支持多人聊天。

2.客户端具有图形化用户界面。

二、设计任务

课程设计说明书(纸质+电子版),内容包括:

设计内容、系统分析(包括可行性分析、需求分析等)及功能分析;系统设计(要求画出系统整体功能框图、流程图、并给出相应地关键的代码且对所使用的主要数据结构进行说明等。

)、设计总结(评价/遇到的问题/体会/建议等)、使用说明等。

三、设计要求

1.按功能要求开发系统,能正确运行。

程序代码书写规范,有充足的注释。

2.课程设计所使用的编程语言任选,但建议使用C或C++;

3.绿色软件:

程序运行不需安装,避免写系统和注册表;

起止日期

工作内容

2011-11-24~2011-11-27

选题

2011-11-28~2011-11-29

系统分析和设计;

2011-11-30~2011-12-3

熟悉软件开发工具、编码系统、系统测试

2011-12-04~2011-12-05

撰写并提交课程设计说明书(含电子文档)、源程序等。

[1](美)LarryPeterson著,薛静锋等译.《计算机网络:

系统方法》(第4版),机械工业出版社,2009

[2](荷)AndrewS.Tanenbaum著,潘爱民译.《计算机网络》(第4版),清华大学出版社,2004

[3]谢希仁著.《计算机网络》((第5版),电子工业出版社,2008.1

[4]吴功宜等著.《计算机网络课程设计》,机械工业出版社,2005

指导教师(签字):

年月日

系(教研室)主任(签字):

年月日

 

课程设计说明书

课程名称:

计算机网络原理

设计题目:

基于UDP协议的聊天程序

专业:

软件工程班级:

092

学生姓名:

蒋政学号:

09408300209

指导教师:

李建设

 

年月日

目录

1.课程设计具体实现过程………………………..4

2.具体代码的实现…………………………………8

3.注意事项………………………………………….12

4.参考文献………………………………………….12

一.多线程编程聊天程序的具体实现

1创建MFC-EXE工程,工程名为Chat,Dialogbased。

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类的InitInstance中调用

if(!

AfxSocketInit())

{

AfxMessageBox("加载套接字库失败!

");

returnFALSE;

}

 

4刚才使用了AfxSocketInit需要加入头文件

#include放入到StdAfx.h的头文件中,StdAfx.h是预编译头文件,包括MFC工程必要的头文件

5在CChatDlg类中定义一个成员函数,作为套接字初始化工作BOOLInitSocket()

同时增加一个变量SOCKETm_socket

6实现InitSocket()

m_socket=socket(AF_INET,SOCK_DGRAM,0);

if(INVALID_SOCKET==m_socket)

{

MessageBox("套接字创建失败!

");

returnFALSE;

}

SOCKADDR_INaddrSock;

addrSock.sin_family=AF_INET;

addrSock.sin_port=htons(1234);

addrSock.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");

intretval;

retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));

intretv=WSAGetLastError();

if(SOCKET_ERROR==retval)

{

closesocket(m_socket);

MessageBox("绑定失败!

");

returnFALSE;

}

returnTRUE;

 

7在CChatDlg的OnInitDialog()的最后调用InitSocket()

8下面编写接收端程序

(1)当接受数据时如果没有数据到来,recvfrom函数会阻塞,从而导致进程暂停运行,所以采用线程来完成

(2)创建线程后,我们需要传递两个参数,一个是套接字,一个是对话框的句柄(接受编辑框的句柄),这样可以通过套接字接受数据,传给接受编辑框,但CreateThread只能传递一个参数(第四个),但是个指针

 

9在CChatDlg的头文件中定义一个结构体

structRECVPARAM

{

SOCKETsock;

HWNDhwnd;

};//注意这里的分号

10在CChatDlg的OnInitDialog()最后,即InitSocket()后

RECVPARAM*pRecvParam=newRECVPARAM;

pRecvParam->sock=m_socket;

pRecvParam->hwnd=m_hWnd;

HANDLEhThread=CreateThread(

NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);

CloseHandle(hThread);

returnTRUE;

11加入线程函数,从MSDN中COPY

加入一个全局函数,有的单位要求不允许使用全局函数,那这里加给CChatDlg类,作为一个成员函数

DWORDWINAPIRecvProc(LPVOIDlpParameter)

 

12此时程序报错,因为要执行RecvProc需要CChatDlg的实例,不能在类中调用,所以报错

解决方法:

在CChatDlg头文件中,将RecvProc函数定义为static类型

 

13实现线程函数

SOCKETsock=((RECVPARAM*)lpParameter)->sock;

HWNDhwnd=((RECVPARAM*)lpParameter)->hwnd;

deletelpParameter;

SOCKADDR_INaddrFrom;

intlen=sizeof(SOCKADDR);

charrecvBuf[200];

chartempBuf[300];

intretval;

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);

//发送数据传送一个自定义消息,传给窗口

}

return0;

 

14加入消息相应机制

(1)在CChatDlg的头文件中定义消息值,加入

#defineWM_RECVDATAWM_USER+1

(2)做一个消息相应函数原型的声明

在CChatDlg的头文件的下方的protected声明中加入

afx_msgvoidOnRecvData(WPARAMwParam,LPARAMlParam);//注意加入了两个参数,因为PostMessage发送消息的过程中传递了参数

(3)加入消息映射:

注意因为CAboutDlg类和CChatDlg类在一个CPP文件中,所以消息映射一定要加正确了

找到BEGIN_MESSAGE_MAP(CChatDlg,CDialog)

在最后面写入:

ON_MESSAGE(WM_RECVDATA,OnRecvData)

第一个参数是消息本身:

WM_RECVDATA

第二个参数是消息相应函数:

OnRecvData

注意后面不要加分号

(4)最后是消息相应函数的实现

在CPP最后加入

voidCChatDlg:

:

OnRecvData(WPARAMwParam,LPARAMlParam)

{

}

 

15实现刚才加入的OnRecvData消息相应函数

CStringstr=(char*)lParam;

CStringstrTemp;

//获取旧文本

GetDlgItemText(IDC_EDIT_RECV,strTemp);

str+="\r\n";//增加一个换行

str+=strTemp;

SetDlgItemText(IDC_EDIT_RECV,str);//放到编辑框

 

16双击发送按钮,系统自动生成按钮相应事件

(1)首先要获取IP,查看MSDN帮助CIPAddressCtrl

CIPAddressCtrl对应的就是IP控件,通过一个DWORD类型的变量来接受IP地址

首先得到控件的指针:

GetDlgItem(IDC_IPADDRESS1)

强制转换为(CIPAddressCtrl*)类型

最后调用CIPAddressCtrl下的一个函数GetAddress

完整的程序是

DWORDdwIP;

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

(2)得到IP地址后,可以发送数据,继续在后面加入代码

SOCKADDR_INaddrTo;

addrTo.sin_family=AF_INET;

addrTo.sin_port=htons(1234);

addrTo.sin_addr.S_un.S_addr=htonl(dwIP);

CStringstrSend;

GetDlgItemText(IDC_EDIT_SEND,strSend);

sendto(m_socket,strSend,strSend.GetLength()+1,0,

(SOCKADDR*)&addrTo,sizeof(SOCKADDR));

SetDlgItemText(IDC_EDIT_SEND,"");

 

17此时发现文本框并没有换行显示选择接收数据的文本框控件,右键选择属性,在Styles中选择Multiline就可以了;

 

18为了让我们回车就发送数据,可以设置发送按钮为缺省按钮,可以右键选择按钮属性,在在Styles中选择Defaultbutton就可以了。

二.具体代码的实现

CPaintDCdc(this);//devicecontextforpainting

SendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);

//Centericoninclientrectangle

intcxIcon=GetSystemMetrics(SM_CXICON);

intcyIcon=GetSystemMetrics(SM_CYICON);

CRectrect;

GetClientRect(&rect);

intx=(rect.Width()-cxIcon+1)/2;

inty=(rect.Height()-cyIcon+1)/2;

//Drawtheicon

dc.DrawIcon(x,y,m_hIcon);

}

else

{

CDialog:

:

OnPaint();

}

}

//Thesystemcallsthistoobtainthecursortodisplaywhiletheuserdrags

//theminimizedwindow.

HCURSORCChartDlg:

:

OnQueryDragIcon()

{

return(HCURSOR)m_hIcon;

}

BOOLCChartDlg:

:

InitSocket()

{

m_socket=socket(AF_INET,SOCK_DGRAM,0);

if(INVALID_SOCKET==m_socket)

{

MessageBox("套接字创建失败!

");

returnFALSE;

}

SOCKADDR_INaddrSock;

addrSock.sin_family=AF_INET;

addrSock.sin_port=htons(1234);

addrSock.sin_addr.S_un.S_addr=inet_addr(GethostIP());

intretval;

retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));

intretv=WSAGetLastError();

if(SOCKET_ERROR==retval)

{

closesocket(m_socket);

MessageBox("绑定失败!

");

returnFALSE;

}

returnTRUE;

}

DWORDWINAPICChartDlg:

:

RecvProc(LPVOIDlpParameter)

{

SOCKETsock=((RECVPARAM*)lpParameter)->sock;

HWNDhwnd=((RECVPARAM*)lpParameter)->hwnd;

deletelpParameter;

SOCKADDR_INaddrFrom;

intlen=sizeof(SOCKADDR);

charrecvBuf[200];

chartempBuf[300];

intretval;

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);

//发送数据传送一个自定义消息,传给窗口

}

return0;

}

voidCChartDlg:

:

OnRecvData(WPARAMwParam,LPARAMlParam)

{

CStringstr=(char*)lParam;

CStringstrTemp;

//获取旧文本

GetDlgItemText(IDC_EDIT_RECV,strTemp);

if(strTemp!

="")strTemp+="\r\n";//增加一个换行

strTemp+=str;

SetDlgItemText(IDC_EDIT_RECV,strTemp);

((CEdit*)GetDlgItem(IDC_EDIT_RECV))->LineScroll(((CEdit*)GetDlgItem(IDC_EDIT_RECV))->GetLineCount());

}

voidCChartDlg:

:

OnButtonSend()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

DWORDdwIP;

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

SOCKADDR_INaddrTo;

addrTo.sin_family=AF_INET;

addrTo.sin_port=htons(1234);

addrTo.sin_addr.S_un.S_addr=htonl(dwIP);

CStringstrSend;

GetDlgItemText(IDC_EDIT_SEND,strSend);

sendto(m_socket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));

SetDlgItemText(IDC_EDIT_SEND,"");

CStringstrTemp;

CStringstr="我说:

"+strSend;

//获取旧文本

GetDlgItemText(IDC_EDIT_RECV,strTemp);

if(strTemp!

="")strTemp+="\r\n";//增加一个换行

strTemp+=str;

SetDlgItemText(IDC_EDIT_RECV,strTemp);

((CEdit*)GetDlgItem(IDC_EDIT_RECV))->LineScroll(((CEdit*)GetDlgItem(IDC_EDIT_RECV))->GetLineCount());

}

LPCSTRCChartDlg:

:

GethostIP()

{

charname[255];

PHOSTENThostinfo;

LPCSTRip;

if(gethostname(name,sizeof(name))==0)

{//如果能获取计算机主机信息的话,则获取本机IP地址

if((hostinfo=gethostbyname(name))!

=NULL)

{

ip=inet_ntoa(*(structin_addr*)*hostinfo->h_addr_list);

}

}

returnip;

}

三.注意事项:

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合金镀层组织形貌及显微硬度研究[J].太原理工大学学报,2001,32

(1):

51-53.(连续出版物:

[序号]主要责任者.文献题名[J].刊名,出版年份,卷号(期号):

起止页码)

[2] 刘国钧,王连成.图书馆史研究[M].北京:

高等教育出版社,1979:

15-18,31.(专著:

[序号]主要责任者.文献题名[M].出版地:

出版者,出版年:

起止页码.)

[3]孙品一.高校学报编辑工作现代化特征[C].中国高等学校自然科学学报研究会.科技编辑学论文集

(2).北京:

北京师范大学出版社,1998:

10-22.(论文集:

[序号]主要责任者.文献题名[C]∥主编.论文集名.出版地:

出版者,出版年:

起止页码.)

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

当前位置:首页 > 求职职场 > 自我管理与提升

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

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