VC++课程设计下了就能用.docx

上传人:b****8 文档编号:9361204 上传时间:2023-02-04 格式:DOCX 页数:27 大小:225.38KB
下载 相关 举报
VC++课程设计下了就能用.docx_第1页
第1页 / 共27页
VC++课程设计下了就能用.docx_第2页
第2页 / 共27页
VC++课程设计下了就能用.docx_第3页
第3页 / 共27页
VC++课程设计下了就能用.docx_第4页
第4页 / 共27页
VC++课程设计下了就能用.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

VC++课程设计下了就能用.docx

《VC++课程设计下了就能用.docx》由会员分享,可在线阅读,更多相关《VC++课程设计下了就能用.docx(27页珍藏版)》请在冰豆网上搜索。

VC++课程设计下了就能用.docx

VC++课程设计下了就能用

 

 

VisualC++程序设计

 

题目名称:

C/S分布式QQ模型聊天室

系名称:

专业班级:

学生姓名:

2011年6月

目录

 

一、成员分工3

二、需求分析3

三、总体设计3

四、详细设计4

五、系统测试18

六、总结20

七、参考文献20

 

一、成员分工

?

?

?

服务器端功能

?

?

?

客户端内容功能

?

?

?

客户端登录功能

 

二、需求分析

当前是数字信息时代,网络时代,任何一种编辑工具都不能忽视在网络上的应用,并且随着Internet的普及和宽带技术的成熟,越来越多的用户进入网络世界中享用浏览新闻、查询信息、发送邮件、在线观看电影等服务,享受网络带来的便利和办公的高效,与此同时一个新型的Web应用程序为网民之间提供了一个实时通信的功能和场所,这就是聊天室。

在网络早期就开始盛行,不论是BBS,IRC都有类似网上聊天室的机制。

聊天室为网友提供了实时性对话的渠道,是网络上极为流行的一项服务。

聊天室适用于网上会议或闲聊的一些场合。

聊天室为网友提供了较好的交友环境,网友之间相互以文字交谈,在形式上有点类似笔友的性质,却大大节省了书信往返的时间,这也是网上交友之所以如此热门的原因。

要求:

掌握CSocket类编程原理

理解客户/服务器通信模块的原理

会用CSocket类编写较复杂的网络通信程序

CSocket对象提供阻塞模式,这对于Carchive的同步操作是至关重要的。

阻塞函数(如Receive()、Send()、ReceiveFrom()、SendTo()和Accept())直到操作完成后才返回控制权。

 

三、总体设计

服务器端核心:

等待客户连接;

通知所有在线用户新登录用户信息;

中转消息;

当用户离线时通知所有在线用户。

客户端核心:

获得连接参数后与服务器建立连接;

发送/接收信息;

断开时通知服务器。

模块流程图:

 

 

四、详细设计

1.服务器端

(1)新建一个基于对话框的MFC项目,命名为ChatRoom,在接下来的“高级功能”选项卡选择“WindowsSockets”复选框。

(2)在对话框上按照表放置相应的控件。

ID

控件类型

标题

风格/变量

IDC_EDIT_INFO

EditBox

ReadOnly||Multiline||VerticalScroll

IDC_STATIC

GroupBox

在线用户

IDC_LIST_USER

ListBox

CListBoxm_UserList

IDOK

ButtonControl

退出

放置控件后的界面如图服务器端。

(3)添加一个新类,命名为CserverSocket,用于接收客户端的连接。

•ServerSocket.h中的定义如下:

#pragmaonce

#include"ClientSocket.h"//CServerSocket命令目标

classCServerSocket:

publicCSocket

{

public:

CPtrListconnectList;//维护客户端连接的socket链表

CServerSocket();

virtual~CServerSocket();

virtualvoidOnAccept(intnErrorCode);//服务器接收客户端的连接

};

•ServerSocket.cpp中的实现,这里只重写了OnAccept()函数:

voidCServerSocket:

:

OnAccept(intnErrorCode)

{

//TODO:

在此添加专用代码和/或调用基类

CClientSocket*clientSocket=newCClientSocket(&connectList);//创建socket用于接收客户端连接

Accept(*clientSocket);//接收新用户连接

clientSocket->m_parent=(CChatRoomDlg*):

:

AfxGetMainWnd();//窗口指针赋值

connectList.AddTail(clientSocket);//加入到链表尾部

CSocket:

:

OnAccept(nErrorCode);

}

(4)再添加一个新类,命名为CClientSocket,用于和客户端进行数据交换。

•ClientSocket.h中的定义:

#pragmaonce

#include"ChatRoomDlg.h"

#include"tagHeader.h"

//CClientSocket命令目标

classCClientSocket:

publicCSocket

{

public:

CStringm_strName;//连接的用户名

CPtrList*clist;//与服务器连接的socket链表指针,所有的socket共享

CChatRoomDlg*m_parent;//维护窗口指针

CClientSocket(CPtrList*list);//构造函数用于将链表共享

CClientSocket();

virtual~CClientSocket();

virtualvoidOnReceive(intnErrorCode);//接收到消息的相关处理

virtualvoidOnClose(intnErrorCode);

};

•ClientSocket.cpp实现

//ClientSocket.cpp:

实现文件

//系统生成的代码略

#include"stdafx.h"

#include"ChatRoom.h"

#include"ClientSocket.h"

#include".\clientsocket.h"

CClientSocket:

:

CClientSocket(CPtrList*list):

m_parent(NULL)

{

clist=list;//链表指针赋值

}

•CClientSocket成员函数

voidCClientSocket:

:

OnReceive(intnErrorCode)

{

//TODO:

在此添加专用代码和/或调用基类

charbuff1[sizeof(Header)];

memset(buff1,0,sizeof(buff1));

Receive(buff1,sizeof(buff1));

Header*header=(Header*)buff1;

intlength=header->len;

chartype=header->type;

if(type==LOGIN_IO)//将接收到的信息是用户的登录或退出信息

{

charbuff[RECV_LEN];

memset(buff,0,sizeof(buff));

Receive(buff,length);

CTimetime=CTime:

:

GetCurrentTime();//得到系统时间

CStringt=time.Format("%Y-%m-%d%H:

%M:

%S");//格式化成字符串

CEdit*p_Edit=(CEdit*):

:

AfxGetMainWnd()->GetDlgItem(IDC_EDIT_INFO);

CStringstrTemp=t+":

"+CString(buff)+"进入聊天室...\r\n";

p_Edit->ReplaceSel(strTemp);//在界面上显示

m_strName=buff;//用户名赋值

m_parent->UpdateUser(this);

}

if(type==SEND_MESSAGE)//将要接收的信息是用户发送的信息

{

charbuf[RECV_LEN];

memset(buf,0,sizeof(buf));

Receive(buf,sizeof(buf));//接收信息

CClientSocket*curr=NULL;

POSITIONpos=clist->GetHeadPosition();

while(pos!

=NULL)//发送给每一个在线用户

{

curr=(CClientSocket*)clist->GetNext(pos);

curr->Send((char*)header,sizeof(Header));

curr->Send(buf,sizeof(buf));

}

}

CSocket:

:

OnReceive(nErrorCode);

}

voidCClientSocket:

:

OnClose(intnErrorCode)

{

//TODO:

在此添加专用代码和/或调用基类

POSITIONpos=clist->Find(this);//找到要退出的Socket对象

if(pos!

=NULL)

{

clist->RemoveAt(pos);//移除

//得到时间等信息再在界面上显示

CTimetime=CTime:

:

GetCurrentTime();

CStringt=time.Format("%Y-%m-%d%H:

%M:

%S");

CEdit*p_Edit=(CEdit*):

:

AfxGetMainWnd()->GetDlgItem(IDC_EDIT_INFO);

CStringstrTemp=t+":

"+this->m_strName+"离开聊天室\r\n";

p_Edit->ReplaceSel(strTemp);

//把退出用户从界面上移掉

m_parent->UpdateUser(this);

this->Close();//Socket对象关闭

deletethis;

}

CSocket:

:

OnClose(nErrorCode);

}

(5)用到的头文件tagHeader.h是这样定义的(后面的客户端也会用到):

typedefstructtagHeader

{

chartype;

intlen;

}Header,*pHeader;//发送的信息头

constintSERVER_PORT=9999;//服务器监听端口

constintLOGIN_IO=1;//登录或退出标记

constintSEND_MESSAGE=3;//发送信息标记

constintRECV_LEN=256;//接收信息长度

constintCLIENT_NUM=50;//聊天室的人数上线

(6)下面是服务器的初始化代码:

BOOLCChatRoomDlg:

:

OnInitDialog()

{

//系统自动生成的代码略

//TODO:

在此添加额外的初始化代码

CServerSocket*m_pSocket;

m_pSocket=newCServerSocket;

if(!

m_pSocket->Create(SERVER_PORT))//创建服务器的监听Socket

{

AfxMessageBox("创建socket失败!

");

returnFALSE;

}

if(!

m_pSocket->Listen())//监听

{

AfxMessageBox("监听发生错误!

");

returnFALSE;

}

((CEdit*)GetDlgItem(IDC_EDIT_INFO))->ReplaceSel("服务器初始化成功...\r\n");//界面显示

returnTRUE;//除非设置了控件的焦点,否则返回TRUE

}

(7)用户登录或者退出时界面上的显示:

//用户的更新,包括用户登录和退出等

voidCChatRoomDlg:

:

UpdateUser(CClientSocket*pSocket)

{

CStringuser_name;//用户名字符串

if(pSocket!

=NULL)

{

m_UserList.ResetContent();//清空过时内容

CClientSocket*pSock=NULL;

POSITIONpos=pSocket->clist->GetHeadPosition();//取得socket链表头

while(pos!

=NULL)//在界面上显示每一个在线用户

{

pSock=(CClientSocket*)pSocket->clist->GetNext(pos);//只要链表不空,依次取下一个位置

m_UserList.AddString(pSock->m_strName);//显示

user_name+=(pSock->m_strName+"&");//用户名赋值

}

Headerhead;//信息头

head.type=LOGIN_IO;//本信息是用户登录或退出信息

head.len=user_name.GetLength();

POSITIONpo=pSocket->clist->GetHeadPosition();

while(po!

=NULL)//向其他的在线用户发送新用户登录信息

{

pSock=(CClientSocket*)pSocket->clist->GetNext(po);

pSock->Send((char*)&head,sizeof(Header));//发送信息头

pSock->Send((LPCTSTR)user_name,user_name.GetLength());//发送新用户的名字

}

}

}

2.客户端

(1)添加一个基于对话框的MFC项目,命名为ChatClient,同样要在“高级功能”选项卡选择“WindowsSockets”复选框。

(2)在对话框上放置如表控件。

ID

控件类型

标题

风格/变量

IDC_STATIC

GroupBox

聊天信息

IDC_EDIT_LIST

EditBox

Mutiline||VerticalScroll

CEditm_MessageList;

IDC_STATIC

GroupBox

在线列表

IDC_LIST_USER

ListBox

CListBoxm_UserList

IDC_EDIT_MESSAGE

EditBox

CStringm_strMessage

ID_SEND

ButtonControl

发送

DefaultButton

IDOK

ButtonControl

退出

 

放置好控件的界面如图客户端所示。

 

注意:

去掉“退出”按钮缺省属性,给“发送”设置缺省属性。

(3)考虑到用户登录时需要添加诸如服务器地址,自己的用户名等信息,我们需要再加入一个对话框资源,命名为IDD_DIALOG_LOGIN,并为该对话框添加类CLoginDlg(基类是CDialog),然后再对话框上按照表放置以下控件。

 

ID

控件类型

标题

风格/变量

IDC_STATIC

GroupBox

登录

IDC_STATIC

StaticText

昵称:

IDC_STATIC

StaticText

服务器IP:

IDC_EDIT_NAME

EditBox

CStringm_strName

IDC_EDIT_SERVER

EditBox

CStringm_strServer

IDOK

ButtonControl

登录

放置控件后的界面如下图所示。

(4)在ChatClient项目中仍然需要一个Socket类CClientSocket来完成数据的发送和接受,具体封装和ChatRoom项目中的CClientSocket封装类似(也可以拷贝并加入到ChatClient项目中修改),下面是具体的封装:

•ClientSocket.h中的定义:

#pragmaonce

#include"tagHeader.h"

classCChatClientDlg;

classCClientSocket:

publicCSocket

{

public:

CChatClientDlg*chatDlg;//窗口指针,便于在界面上显示信息

CClientSocket();

virtual~CClientSocket();

virtualvoidOnReceive(intnErrorCode);//接收信息

};

•ClientSocket.cpp中的实现:

//CClientSocket成员函数

voidCClientSocket:

:

OnReceive(intnErrorCode)

{//根据type字段决定是接收信息或者是用户登录/退出消息

//TODO:

在此添加专用代码和/或调用基类

charbuf[sizeof(Header)];//用于接收消息头的缓冲区

memset(buf,0,sizeof(buf));

Receive(buf,sizeof(buf));//接收消息头

Header*header=(Header*)buf;//强制转换成消息头结构

intlength=header->len;

chartype=header->type;

if(type==SEND_MESSAGE)//发送的是信息

{

chatDlg->GetMessage();//接收信息

}

if(type==LOGIN_IO)//是用户登录/退出消息

{

chatDlg->UpdateUser();//处理用户登录或退出消息

}

CSocket:

:

OnReceive(nErrorCode);

}

(5)因为在两个对话框(即“登录”对话框和主聊天对话框)中都用到同一个Socket对象,所以有必要在CChatClientApp主程序中定义一个全局的客户端Socket对象,同时修改两个对话框的构造函数,具体如下:

•ClientSocket.h中对CClientSocket类的定义:

#pragmaonce

#include"tagHeader.h"

//CClientSocket命令目标

classCChatClientDlg;

classCClientSocket:

publicCSocket

{

public:

CChatClientDlg*chatDlg;//窗口指针,便于在界面上显示信息

CClientSocket();

virtual~CClientSocket();

virtualvoidOnReceive(intnErrorCode);//接收信息

};

•ClientSocket.cpp中的实现:

//ClientSocket.cpp:

实现文件

//系统生成的代码略

#include"stdafx.h"

#include"ChatClient.h"

#include"ClientSocket.h"

#include".\clientsocket.h"

#include"ChatClientDlg.h"

//CClientSocket成员函数

voidCClientSocket:

:

OnReceive(intnErrorCode)

{//根据type字段决定是接收信息或者是用户登录/退出消息

//TODO:

在此添加专用代码和/或调用基类

charbuf[sizeof(Header)];//用于接收消息头的缓冲区

memset(buf,0,sizeof(buf));

Receive(buf,sizeof(buf));//接收消息头

Header*header=(Header*)buf;//强制转换成消息头结构

intlength=header->len;

chartype=header->type;

if(type==SEND_MESSAGE)//发送的是信息

{

chatDlg->GetMessage();//接收信息

}

if(type==LOGIN_IO)//是用户登录/退出消息

{

chatDlg->UpdateUser();//处理用户登录或退出消息

}

CSocket:

:

OnReceive(nErrorCode);

}

•CLoginDlg构造函数的改写:

注意:

为了便于本地测试,程序默认服务器IP地址为本地IP地址。

//CLoginDlg对话框

IMPLEMENT_DYNAMIC(CLoginDlg,CDialog)

CLoginDlg:

:

CLoginDlg(CClientSocket*p_Socket,CWnd*pParent/*=NULL*/)

:

CDialog(CLoginDlg:

:

IDD,pParent)

m_strName(_T(""))

m_strServer(_T(""))

//获取本地IP地址并默认指示为服务器IP

{

charHostName[128];

structhostent*pHost;

CStringstr;

if(gethostname(HostName,128)==0)

{

pHost=gethostbyname(HostName);

for(inti=0;pHost!

=NULL&&pHost->h_addr_list[i]!

=NULL;++i)

{

str=inet_ntoa(*(structin_addr*)pHost->h_addr_list[i]);

}

}

m_pSocket=p_Socket;

m_strServer=str;

str.Empty();

}

•CChatClientDlg构造函数的改写:

//CChatClientDlg对话框

CChatClientDlg:

:

CChatClientDlg(CClientSocket*p_Socket,CWnd*pParent/*=NULL*/)

:

CDialog(CChatClientDlg:

:

IDD,pParent)

m_strMessage(_T("")

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

当前位置:首页 > 小学教育 > 英语

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

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