当前位置:文档之家› VC++课程设计报告

VC++课程设计报告

VC++课程设计报告
VC++课程设计报告

H a r b i n I n s t i t u t e o f T e c h n o l o g y a t W e i h a i

课程设计报告

课程名称:VC++课程设计

设计题目:聊天室程序设计

院系:计算机科学与技术系班级:

设计者:

学号:

指导教师:

设计时间:2011.8.25-----2011.9.7 哈尔滨工业大学(威海)

《VC++课程设计》验收及成绩评定表(项目组)

《VC++课程设计》验收及成绩评定表(项目组)

哈尔滨工业大学(威海)课程设计任务书

VC++课程设计报告

软硬件运行环境:

Intel? Pentium? 2及以上处理器,32M以上内存,4G以上硬盘

Microsoft? Windows? XP操作系统及以上版本

800*600或以上的屏幕分辨率

开发环境:

Intel? CORE i5? 2.8 GHz,2内存,320G硬盘

Microsoft? Windows? XP Professional

Microsoft? Visual C++ 6.0

问题及难点所在

要解决的问题:

如何与服务器端建立连接,如何接收服务器端发给客户端的消息,相应的处理这些消息。还有就是如何提取出服务器端发给客户端的所有的客户昵称,然后更新客户端的用户列表。最后是一些按钮的响应函数的编写。

涉及算法的思想

首先应该明白,Windows窗口应用程序是基于消息驱动的,这应该是贯穿整个过程的基本思想。

其次跟据MFC程序的体系结构,和大体框架,清楚自己写的代码应该加在哪些地方。实际编程中善于将控件窗口与一个变量相联系,可以很大的简化操作。特别要提到的是程序中更新用户列表的方法,与服务器端的算法刚好相反,充分利用FOR循环并用IF判断语句来提取信息。

系统的流程图

注:这个流程图是在另一个文档中画的,完成后复制过来发现尺寸不是很好,显示得很难看,所以采用了截图的方法,清晰度不是很高,望老师体谅。

系统的设计与分析

第一个函数:

void CLoginDlg::OnOK() //登陆窗口的登陆按钮响应函数。

{

UpdateData();//用来刷新数据的,如果参数为真,则刷新控件的值到对应的变量,若为假,则方向相反。

// m_pSocket->m_strName = this->m_strName;

if(!m_pSocket->Create())//创建。

AfxMessageBox("网络创建错误!!!");

m_pSocket->Close();

return;

}

if(!m_pSocket->Connect(m_strServer,9999))//连接,参数分别为服务器IP和端口号。

{

AfxMessageBox("连接服务器失败!!!");

m_pSocket->Close();

return;

}

Header head;

head.type = LOGIN_IO;

head.len = m_strName.GetLength();

m_pSocket->Send((char *)&head,sizeof(Header));//向服务器端发送预备消息,告知消息类型,准备好接受数据。

m_pSocket->Send(m_strName,m_strName.GetLength());//发送该客户端的用户昵称。

theApp.m_strName = m_strName;//如果不加此行,用户的昵称将无法显示到聊天窗口

CDialog::OnOK();//调用基类的ONOK函数,MFC自动调用的。

}

第二个函数:

void CClientSocket::OnReceive(int nErrorCode) //处理服务器端发送的消息

{

char buff[sizeof(Header)];

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

Receive(buff,sizeof(buff));

Header *header = (Header*)buff;//这里需要一个类型的转换。

int length = header->len;

char type = header->type;

if(type == SEND_MESSAGE)

chatDlg->GetMessage();//定义一个CMyChatDlg *类型的chatDlg变量作用就在此体现。

}

if(type == LOGIN_IO)//收到服务器告知的更新用户的消息。

{

chatDlg->UpdateUser(); //调用CMyChatDlg类中的UpdateUser方法。

}

CSocket::OnReceive(nErrorCode);

}

第三个函数:

void CMyChatDlg::UpdateUser()//更新用户列表。

{

char buff[1000];

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

m_pSocket->Receive(buff, sizeof(buff),0);

CString user_info = buff;

CString array[100];//存放用户名称

int b = 0;

for( int i=0; i

{

if(i != (user_info.GetLength() - 1))//判断是否已经到达UER_INFO的尾端。

{

if ( user_info[i]=='&' )//判断是否已经到一个昵称的结尾。

{

b ++;//用户加一

}

else

{

array[b] = array[b] + user_info[i];//将一个用户名称拷贝到一个数组单元中。

}

}

m_num.Format("%d", b+1);//将INT类型的b转换为CString类型。

UpdateData(FALSE);//变量到控件。

m_UserList.ResetContent();//置空列表框。

for(int j=0; j

{

m_UserList.AddString(array[j]);//将转换好的用户名称依次显示出来。

}

}

第四个函数:

void CMyChatDlg::OnSend() //响应发送按钮的函数。

{

UpdateData();//控件的值—>变量

if(m_strMessage == "")

{

AfxMessageBox("不能发送空消息!!!");

CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT_MESSAGE);//得到该控件类型的对象地址。

pEdit->SetFocus();//调用成员函数设置焦点。

return;

}

Header head;

head.type = SEND_MESSAGE;

head.len = m_strMessage.GetLength();

CTime time = CTime::GetCurrentTime();//得到系统当前时间。

CString t = time.Format("%H:%M:%S");//设置时间格式。

CString nikeName = theApp.m_strName;

CString str =nikeName+ " " + t + "\r\n" +m_strMessage;//把要发送的信息都存储在这str变量中。

m_pSocket->Send((char *)&head,sizeof(Header));//发送“头信息”。

// TODO: Add your control notification handler code here

if(m_pSocket->Send((LPCTSTR)str, str.GetLength()))//发送用户编辑的信息,并判断Send函数的返回值。

m_strMessage = "";

UpdateData(FALSE);//变量—>控件的值

CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT_MESSAGE);

pEdit->SetFocus();

}

else

{

AfxMessageBox("网络传输错误!");

}

}

第五个函数:

BOOL CMyChatDlg::GetMessage()//由CClientSocket对象中的OnReceive方法调用。

{

char buff[1000];//定义一个数组来接受消息。

memset(buff,0,sizeof(buff));//将数组全部初始化为0。

m_pSocket->Receive(buff, sizeof(buff),0);//接受消息。

CString strTemp = buff;

strTemp += _T("\r\n");

m_MessageList.ReplaceSel(strTemp);//用strTemp变量中的内容替换消息显示框控件的当前区域。

return TRUE;

}

运行结果与分析(测试)

打开服务器并初始化

一个用户登陆服务器

客户端发送了一条消息

第二个用户登陆

两个用户之间聊天

昵称为唐毅的用户离开聊天室

昵称为烟灰缸的用户离开聊天室 总结(收获与体会)

附:源代码

注:以下代码包括了一点VC自动帮我们生成的部分。

客户端源代码:

CMyChatApp类中的InitInstance方法:

BOOL CMyChatApp::InitInstance()//初始化实例。

{

if (!AfxSocketInit())//初始化WINSOCK环境,一旦选择支持WINSOCKET类则由MFC为我们自动生成。

{

AfxMessageBox(IDP_SOCKETS_INIT_FAILED);

return FALSE;

}

AfxEnableControlContainer();

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need.

#ifdef _AFXDLL

Enable3dControls(); // Call this when using MFC in a shared DLL #else

Enable3dControlsStatic(); // Call this when linking to MFC statically #endif

CClientSocket *clientSocket;

clientSocket = new CClientSocket();//NEW一个CClientSocket对象,用来之后与服务器端建立连接。

CLoginDlg* loginDlg;

loginDlg = new CLoginDlg(clientSocket);//NEW一个CLoginDlg对象。

if(loginDlg->DoModal() == IDCANCEL)//显示这个登陆窗口,并判断返回值是否来IDCANCEL,如是

{

delete clientSocket;

delete loginDlg;//则delete这两个对象。

return false;//返回false后程序结束。

}

else

{

delete loginDlg;//如果用户点击的是登陆按钮,则会调用对应的消息处理函数,并delete这个登陆窗口对象。

}

CMyChatDlg *dlg;

dlg = new CMyChatDlg(clientSocket);

m_pMainWnd = dlg;//m_pMainWnd是CWinThread(是CMyApp的基类)的一个成员变量,用于储存一个指向我们创建的一个线程的主窗口的对象。

int nResponse = dlg->DoModal();//显示客户端主窗口,并接受函数的返回值。

return FALSE;

}

在CMyChatApp类中的成员变量:

CString m_strName;

定义了一个结构体:

typedef struct tagHeader

{

char type;

int len;

} Header, *pHeader;

#define LOGIN_IO 1

#define SEND_MESSAGE 3

客户端套接字类中的OnReceive成员函数:

void CClientSocket::OnReceive(int nErrorCode)

{

// TODO: Add your specialized code here and/or call the base class

char buff[sizeof(Header)];

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

Receive(buff,sizeof(buff));

Header *header = (Header*)buff;//这里需要一个类型的转换。

int length = header->len;

char type = header->type;

if(type == SEND_MESSAGE)

{

chatDlg->GetMessage();//定义一个CMyChatDlg *类型的chatDlg变量作用

就在此体现。

}

if(type == LOGIN_IO)//收到服务器告知的更新用户的消息。

{

chatDlg->UpdateUser(); //调用CMyChatDlg类中的UpdateUser方法。

}

CSocket::OnReceive(nErrorCode);

}

在这个类中还定义了两个公有的成员变量:

CMyChatDlg *chatDlg;//用来调用主窗口中的GetMessage和UpdateUser方法。CString m_strName;//存放该客户端的昵称。

登陆窗口类的构造函数:

CLoginDlg::CLoginDlg(CClientSocket *p_Socket, CWnd* pParent /*=NULL*/)//创建它的对象的时候需要传递它一个CClientSocket对象

: CDialog(CLoginDlg::IDD, pParent)//的地址,用来建立连接。

{

ASSERT(p_Socket);//断言assert是一个宏,一般可以用在判断某件操作是否成功上。

m_pSocket = p_Socket;//提取传递进来的参数。

//{{AFX_DATA_INIT(CLoginDlg)

m_strName = _T("");

m_strServer = _T("127.0.0.1");//_T是一个宏,这里的作用相当于初始化了这两个控件的值。

//}}AFX_DATA_INIT

}

登陆窗口的确定按钮响应函数:

void CLoginDlg::OnOK()

{

// TODO: Add extra validation here

UpdateData();//用来刷新数据的,如果参数为真,则刷新控件的值到对应的变量,若为假,则方向相反。

// m_pSocket->m_strName = this->m_strName;

if(!m_pSocket->Create())//创建。

{

相关主题
文本预览
相关文档 最新文档