基于UDP协议的聊天工具的设计研究生课程论文.docx

上传人:b****7 文档编号:11216208 上传时间:2023-02-25 格式:DOCX 页数:30 大小:291.69KB
下载 相关 举报
基于UDP协议的聊天工具的设计研究生课程论文.docx_第1页
第1页 / 共30页
基于UDP协议的聊天工具的设计研究生课程论文.docx_第2页
第2页 / 共30页
基于UDP协议的聊天工具的设计研究生课程论文.docx_第3页
第3页 / 共30页
基于UDP协议的聊天工具的设计研究生课程论文.docx_第4页
第4页 / 共30页
基于UDP协议的聊天工具的设计研究生课程论文.docx_第5页
第5页 / 共30页
点击查看更多>>
下载资源
资源描述

基于UDP协议的聊天工具的设计研究生课程论文.docx

《基于UDP协议的聊天工具的设计研究生课程论文.docx》由会员分享,可在线阅读,更多相关《基于UDP协议的聊天工具的设计研究生课程论文.docx(30页珍藏版)》请在冰豆网上搜索。

基于UDP协议的聊天工具的设计研究生课程论文.docx

基于UDP协议的聊天工具的设计研究生课程论文

研究生课程论文

课程名称面向对象程序设计VC++

学院电子工程学院

专业电子与通信工程

 

基于UDP协议的聊天工具的设计

第1章需求分析

1.1功能需求

1 用户之间能够通过输入IP地址建立连接

2 用户能够输入所需发送的信息,并能够在界面上发看到输入的信息

3 用户之间可以相互通信

1.2应用平台需求

安装有VS2008的操作系统,能够正常运行EXE文件。

1.3界面的设计需求

本程序利用UDP协议来进行通信,因此可以简单地将发送端和接收端集成在同一个对话框界面上,并可以通过利用多线程技术以保证接受信息功能的顺畅。

1.4简单流程图

图1-1

第2章概要设计

2.1程序总体结构图

发送端接收端

创建套接字

输入消息

创建接收线程

显示消息

实现线程函数

发送消息

消息转换

接受消息

 

图2-1

 

2.2发送端流程

发送消息

显示消息

输入消息

创建套接字

图2-2

2.3接收端流程

消息转换

接受消息

实现线程函数

创建接收线程

 

图2-3

 

第3章详细设计

3.1界面设计

图3-1

说明:

界面由一个对话框,两个编辑框,一个按钮和一个IP地址编辑框组成。

其中接收数据栏中的编辑框可以显示发送的信息和接收到的信息,发送数据栏中编辑框则可以编辑发送信息,按回车键后即可发送信息。

IP地址栏中可以输入需要连接的主机的IP地址。

为了美观和方便,在添加按钮后,选中按钮控件的DEFAULT和VISIALBE属性,将其设定为不可见,并通过回车能够实现按钮功能。

 

3.2多线程

由于该聊天工具是将利用UDP协议实现聊天功能,并将发送端和接收端(某种意义上也可以算是服务器和客户端)集成在一起,为了将发送功能和接受功能同时实现,需要用到多线程技术。

因为在接收端接收数据时,如果数据没有来到,recvfrom函数会阻塞,从而导致程序暂停运行。

所以,将接收数据的操作放置在一个单独的线程中完成。

并给这个线程函数传递两个参数,一个是已创建的套接字,一个是对话框空间的句柄,这样,在该函数中,当接到数据后,可以将该数据传回给对话框,经过处理后显示在接受编辑框控件上。

传递的结构体的代码如下:

structRECVPARAM

{

SOCKETsock;//已创建的套接字

HWNDhwnd;//对话框句柄

};

编写接受线程函数,并在一定情况下启动线程,具体代码请参阅附录。

 

3.3套接字

因为本程序使用的是UDP协议,并将接收端和发送端集成在一个面上,所以从理论上说,该界面即是服务器,又是客户端,而且基于UDP协议的聊天工具的套接字中并不需要监听和接受的步骤,彼此是点对点式的平等,也正是因此,所以可以将服务器和客户端集成在一起。

 

第四章测试结果

图4-1

 

第五章总结

这次课程设计对我来说是一个重大的挑战,因为从前没有学过C++,并对网络编程、套接字、多线程一无所知,所以遇到的困难很大。

不过好在老师的指导和自己通过网络,图书馆等途径的查询,终于搞明白了其中的大部分内容,这次课程设计对我的VC是一个检验,更加是是对我学习能力的一个检验。

在编写代码的过程中,所用到的技术基本上都能够从书上查到,并通过自己的揣摩能够编写,但是最后遇到了一个最大的问题,就是通过127.0.0.1的自网测试没有问题,但是在不同电脑相互通信的时候,往往套接字创建失败,这个问题一直困扰了我很长的时间,不管我怎么看代码都找不出其中的原因。

后来通过网络相关论坛的帮助,我才明白,原来Windows系统的防火墙对端口6000有限制,所以如果将套接字绑定在端口6000上,无法实现创建套接字,因此总是会不断地失败。

只需要改为其他的端口,即可在不同电脑之间的相互通信。

这算是我通过这次的课程设计所收获到的一个很大的知识点,也算是我的一个小礼物。

这次课程设计是我和我的同学一起完成的,我们通过相互的讨论和研究,终于完成了这个聊天程序,我们的合作很愉快,也非常感谢老师的帮助,希望我们在以后的学习中能够迎接新的挑战。

 

第六章关键源程序

AfxSocketInit()是一个BOOL型函数,作用是初始化套接字,成功返回非0,不成功返回0。

if(!

AfxSocketInit())//判断这个函数是否为0

{

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

");//为0会有提示

returnFALSE;//返回FALSE,关闭

}

else

{

AfxMessageBox("加载套接字库成功!

");

}

 

InitSocket()函数用来初始化套接字,并和本地信息进行绑定。

BOOLCChatDlg:

:

InitSocket()

{

m_socket=socket(AF_INET,SOCK_DGRAM,0);/*用变量m_socket接收创建的套接字。

Socket()是1个创建套接字的函数,如果创建不成功,返回INVALID_SOCKET。

*/

if(m_socket==INVALID_SOCKET)/*如果创建套接字失败,则返回FALSE。

*/

{

MessageBox("创建套接字失败!

");

returnFALSE;

}

SOCKADDR_INaddrSock;/*定义SOCKADDR_IN类型结构体addrSock*/

//给结构体里的各个变量进行赋值。

addrSock.sin_family=AF_INET;//用网际域

addrSock.sin_port=htons(5000);/*端口为5000,用htons函数转换成网络字节序*/

//获取主机IP地址,并赋值给结构体内变量。

addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

//用bind函数将本地地址和建立的套接字进行绑定。

intretval;

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

//进行判断,如果绑定失败,关闭套接字,进行消息提示,返回FALSE。

if(SOCKET_ERROR==retval)

{

closesocket(m_socket);

MessageBox("套接字与本地机地址绑定失败!

");

returnFALSE;

}

else

{

MessageBox("套接字与本地机地址绑定成功!

");

}

returnTRUE;

}

建立1个结构体RECVPARAM,并用指针pRecvParam指向它。

RECVPARAM*pRecvParam=newRECVPARAM;/*用new给指针分配1个动态空间*/

pRecvParam->hwnd=m_hWnd;//给结构体变量赋初值,传递对话框句柄

pRecvParam->sock=m_socket;//传递套接字

 

用CreateThread创建一个新的线程,然后创建线程句柄hThread,用来接收CreateThread返回的句柄值。

HANDLEhThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);

CloseHandle(hThread);/*关闭新线程的句柄,递减线程内核对象的使用计数。

*/

新线程执行函数RecvProc()

DWORDWINAPICChatDlg:

:

RecvProc(LPVOIDlpParameter)

{

//取出所传递的2个参数值,1个是套接字,1个是对话框句柄。

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

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

SOCKADDR_INaddrFrom;/*定义1个套接字地址结构变量,接收发送端的地址信息。

*/

intlen=sizeof(SOCKADDR);//接收返回地址结构体的长度。

charrecvBuf[100];//字符数组,用来接收到来的数据。

chartempBuf[100];//用来存放格式化后的数据。

intretval;

while(TRUE)//做一个循环,让它不断接收数据

{

retval=recvfrom(sock,recvBuf,100,0,//retval接收recvfrom的返回值

(SOCKADDR*)&addrFrom,&len);

if(retval==SOCKET_ERROR)/*如果返回SOCKET_ERROR,调用break语句,终止循环。

*/

{

break;

}

//如果无错误,格式化recvBuf,将格式化后的数据放入tempBuf中。

sprintf(tempBuf,"%s说:

%s",inet_ntoa(addrFrom.sin_addr),

recvBuf);/*调用inet_ntoa,将发送端IP地址转换为点分十进制字符串*/

//将接收到的数据传递给对话框。

:

:

PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);

}

return0;

}

 

对接收到的消息进行处理,使得能够按照一定格式输出。

对于接收数据框来说,接收到的最新数据应该放到最顶端,以前的数据应该依次往下排列。

voidCChatDlg:

:

OnRecvData(WPARAMwParam,LPARAMlParam)

{

CStringstr=(char*)lParam;//把lParam转换成字符型指针,然后赋给str。

CStringstrTemp;//接收旧的数据。

GetDlgItemText(IDC_EDIT_RECV,strTemp);//从控件中得到文本。

str+="\r\n";//让新的数据加1个换行。

str+=strTemp;//再下一行加入先前的数据。

SetDlgItemText(IDC_EDIT_RECV,str);//将数据放回接收的编辑框。

}

 

发送函数

voidCChatDlg:

:

OnBtnSend()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

DWORDdwIP;//定义DWORD类型变量,用来接收控件的IP地址。

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);//通过GetDlgItem,得到控件的CWnd指针,再转换类型,得到dwIP。

SOCKADDR_INaddrTo;//定义地址结构体变量。

addrTo.sin_family=AF_INET;

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

addrTo.sin_port=htons(5000);

CStringstrSend;

GetDlgItemText(IDC_EDIT_SEND,strSend);/*得到编辑框的文本,传递给strSend。

*/

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

(SOCKADDR*)&addrTo,sizeof(SOCKADDR));//发送数据。

SetDlgItemText(IDC_EDIT_SEND,"");/*发送完后将编辑文本框设置为空。

*/

 

}

 

附录

在ChatApp类中的IniInstance(void)函数中添加一段代码:

if(!

AfxSocketInit())

{

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

");

returnFALSE;

}

else

{

AfxMessageBox("加载套接字库成功!

");

}

以下是ChatDlg.cpp中实现的代码:

//ChatDlg.cpp:

implementationfile

//

#include"stdafx.h"

#include"Chat.h"

#include"ChatDlg.h"

#ifdef_DEBUG

#definenewDEBUG_NEW

#undefTHIS_FILE

staticcharTHIS_FILE[]=__FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

//CAboutDlgdialogusedforAppAbout

classCAboutDlg:

publicCDialog

{

public:

CAboutDlg();

//DialogData

//{{AFX_DATA(CAboutDlg)

enum{IDD=IDD_ABOUTBOX};

//}}AFX_DATA

//ClassWizardgeneratedvirtualfunctionoverrides

//{{AFX_VIRTUAL(CAboutDlg)

protected:

virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport

//}}AFX_VIRTUAL

//Implementation

protected:

//{{AFX_MSG(CAboutDlg)

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

CAboutDlg:

:

CAboutDlg():

CDialog(CAboutDlg:

:

IDD)

{

//{{AFX_DATA_INIT(CAboutDlg)

//}}AFX_DATA_INIT

}

voidCAboutDlg:

:

DoDataExchange(CDataExchange*pDX)

{

CDialog:

:

DoDataExchange(pDX);

//{{AFX_DATA_MAP(CAboutDlg)

//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)

//{{AFX_MSG_MAP(CAboutDlg)

//Nomessagehandlers

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

//CChatDlgdialog

CChatDlg:

:

CChatDlg(CWnd*pParent/*=NULL*/)

:

CDialog(CChatDlg:

:

IDD,pParent)

{

//{{AFX_DATA_INIT(CChatDlg)

//NOTE:

theClassWizardwilladdmemberinitializationhere

//}}AFX_DATA_INIT

//NotethatLoadIcondoesnotrequireasubsequentDestroyIconinWin32

m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

voidCChatDlg:

:

DoDataExchange(CDataExchange*pDX)

{

CDialog:

:

DoDataExchange(pDX);

//{{AFX_DATA_MAP(CChatDlg)

//NOTE:

theClassWizardwilladdDDXandDDVcallshere

//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CChatDlg,CDialog)

//{{AFX_MSG_MAP(CChatDlg)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_BN_CLICKED(IDC_BTN_SEND,OnBtnSend)

//}}AFX_MSG_MAP

ON_MESSAGE(WM_RECVDATA,OnRecvData)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

//CChatDlgmessagehandlers

BOOLCChatDlg:

:

OnInitDialog()

{

CDialog:

:

OnInitDialog();

//Add"About..."menuitemtosystemmenu.

//IDM_ABOUTBOXmustbeinthesystemcommandrange.

ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX<0xF000);

CMenu*pSysMenu=GetSystemMenu(FALSE);

if(pSysMenu!

=NULL)

{

CStringstrAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if(!

strAboutMenu.IsEmpty())

{

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);

}

}

//Settheiconforthisdialog.Theframeworkdoesthisautomatically

//whentheapplication'smainwindowisnotadialog

SetIcon(m_hIcon,TRUE);//Setbigicon

SetIcon(m_hIcon,FALSE);//Setsmallicon

//TODO:

Addextrainitializationhere

InitSocket();

RECVPARAM*pRecvParam=newRECVPARAM;

pRecvParam->hwnd=m_hWnd;

pRecvParam->sock=m_socket;

HANDLEhThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);

CloseHandle(hThread);

this->SetWindowText("ChatWindow");

returnTRUE;//returnTRUEunlessyousetthefocustoacontrol

}

voidCChatDlg:

:

OnSysCommand(UINTnID,LPARAMlParam)

{

if((nID&0xFFF0)==IDM_ABOUTBOX)

{

CAboutDlgdlgAbout;

dlgAbout.DoModal();

}

else

{

CDialog:

:

OnSysCommand(nID,lParam);

}

}

//Ifyouaddaminimizebuttontoyourdialog,youwillneedthecodebelow

//todrawtheicon.ForMFCapplicationsusingthedocument/viewmodel,

//thisisautomaticallydoneforyoubytheframework.

voidCChatDlg:

:

OnPaint()

{

if(IsIconic())

{

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.

HCURSORCChatDlg:

:

OnQueryDragIcon()

{

return(HCURSOR)m_hIcon;

}

BOOLCChatDlg:

:

InitSocket()

{

m_socket=socket(AF_INET,SOCK_DGRAM,0);//创建套接字

if(m_socket==INVALID_SOCKET)

{

MessageBox("创建套接字失败!

");

returnFALSE;

}

//初始化套接字

SOCKADDR_INaddrSock;

addrSock.sin_family=AF_INET;

addrSock.sin_port=htons(5000);

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

当前位置:首页 > 经管营销 > 经济市场

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

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