MFC+Winsock类cs聊天程序开发.docx

上传人:b****6 文档编号:6048802 上传时间:2023-01-03 格式:DOCX 页数:16 大小:142.78KB
下载 相关 举报
MFC+Winsock类cs聊天程序开发.docx_第1页
第1页 / 共16页
MFC+Winsock类cs聊天程序开发.docx_第2页
第2页 / 共16页
MFC+Winsock类cs聊天程序开发.docx_第3页
第3页 / 共16页
MFC+Winsock类cs聊天程序开发.docx_第4页
第4页 / 共16页
MFC+Winsock类cs聊天程序开发.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

MFC+Winsock类cs聊天程序开发.docx

《MFC+Winsock类cs聊天程序开发.docx》由会员分享,可在线阅读,更多相关《MFC+Winsock类cs聊天程序开发.docx(16页珍藏版)》请在冰豆网上搜索。

MFC+Winsock类cs聊天程序开发.docx

MFC+Winsock类cs聊天程序开发

案例开发和分析——聊天程序的开发

一、客户端

任务1:

创建客户端框架程序,设计用户界面,并实现和服务器的连接。

1.创建一个空白工作区,并命名为Chat。

2.在Chat工作区,用MFCAppWizard创建基于对话框的项目ChatClient,并在Step2中选中WindowsSocket选项。

3.在对话框中添加控件,如下图所示:

4.对话框中的控件属性如下表:

表1控件属性

控件类型

控件ID

Caption

其他

ListBox

IDC_LIST_MESSAGE

不选Sort

ListBox

IDC_LIST_ONLINE_USERS

不选Sort

EditBox

IDC_EDIT_MESSAGE

选中Multiline和VerticalScroll

RadioButton

IDC_RADIO_GROUP

群聊

RadioButton

IDC_RADIO_PRIVATE

私聊

Button

IDC_BUTTON_LOGIN

登录

Button

IDC_BUTTON_LOGOUT

退出

5.用ClassWizard为控件对象定义相应的成员变量,如下表所示:

表2控件对应成员变量

控件ID

控件类型

成员变量名

IDC_EDIT_MESSAGE

CString

m_strMessage

IDC_LIST_MESSAGE

CListBox

m_listMessage

IDC_LIST_ONLINE_USERS

CListBox

m_listUsers

6.添加对话框,ID为IDD_DIALOG_LOGIN,Caption为“登录”。

7.在对话框中添加控件,如下图所示:

8.对话框中的控件属性如下:

表3登录对话框控件属性

控件类型

控件ID

Caption

其他

EditBox

IDC_EDIT_IP

EditBox

IDC_EDIT_PORT

EditBox

IDC_EDIT_USERNAME

EditBox

IDC_EDIT_PASSWORD

选Styles->Password

Button

IDOK

连接

选Styles->DefaultButton

Button

IDCANCEL

取消

9.添加一个新类,类名为CLoginDlg,基类为CDialog,DialogID为IDD_DIALOG_LOGIN。

10.用ClassWizard为对话框的控件对象定义成员变量,如下表所示:

表4登录对话框控件对应成员变量

控件ID

控件类型

成员变量名

IDC_EDIT_IP

CString

m_strIP

IDC_EDIT_PASSWORD

CString

m_strPassword

IDC_EDIT_PORT

UINT

m_nPort

IDC_EDIT_USERNAME

CString

m_strUserName

11.为CChatClientDlg类添加“登录”按钮的单击事件消息处理函数OnButtonLogin(),并添加如下代码:

CLoginDlgdlg;

intnRet=-1;

nRet=dlg.DoModal();

12.在ChatClientDlg.cpp中添加:

#include"LoginDlg.h"。

编译项目并运行,单击登录按钮,看看运行情况。

此时单击退出按钮无反应,tellmewhy?

13.添加一个从CSocket类派生的新类CMySocket,添加类型为CChatClientDlg*的成员变量m_pDlg,并修改默认构造函数和析构函数如下:

(注意,也应修改类声明中的构造函数原型)

CMySocket:

:

CMySocket(CChatClientDlg*pDlg)

{

m_pDlg=pDlg;

}

CMySocket:

:

~CMySocket()

{

m_pDlg=NULL;

}

在CMySocket类的头文件中,添加前置声明:

classCChatClientDlg;。

14.为CChatClientDlg类添加类型为CMySocket*的成员变量m_pMySocket,类型为BOOL的成员变量m_bGroupChat。

在CChatClientDlg类的头文件中,添加前置声明:

classCMySocket;。

15./////在CChatClientDlg:

:

OnInitDialog()中添加如下代码:

//TODO:

Addextrainitializationhere

m_bGroupChat=TRUE;//默认聊天方式为群聊

((CButton*)GetDlgItem(IDC_RADIO_GROUP))->SetCheck(TRUE);//设置群聊按钮被选中

((CButton*)GetDlgItem(IDC_BUTTON_LOGOUT))->EnableWindow(FALSE);((CEdit*)GetDlgItem(IDC_EDIT_MESSAGE))->EnableWindow(FALSE);//设置编辑框不可用

16.在CChatClientDlg类的OnButtonLogin()中添加如下代码:

voidCChatClientDlg:

:

OnButtonLogin()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

CLoginDlgdlg;

intnRet=-1;

nRet=dlg.DoModal();

//新增加的代码

switch(nRet)

{

caseIDOK:

m_pMySocket=newCMySocket(this);

if(!

m_pMySocket->Create())

{

deletem_pMySocket;

m_pMySocket=NULL;

AfxMessageBox("创建套接字失败!

");

return;

}

if(!

m_pMySocket->Connect(dlg.m_strIP,dlg.m_nPort))

{

deletem_pMySocket;

m_pMySocket=NULL;

AfxMessageBox("连接服务器失败!

");

return;

}

((CButton*)GetDlgItem(IDC_BUTTON_LOGOUT))->EnableWindow(TRUE);

((CButton*)GetDlgItem(IDC_BUTTON_LOGIN))->EnableWindow(FALSE);

((CEdit*)GetDlgItem(IDC_EDIT_MESSAGE))->EnableWindow(TRUE);

break;

caseIDCANCEL:

break;

default:

break;

}

}

在CChatClientDlg类的实现文件中,包含CMySocket类的头文件,即:

#include"MySocket.h"。

编译项目并运行,单击登录按钮,看看运行情况。

注意:

C++头文件不能相互包含,详情可参考以下链接

二、服务器端

任务1:

创建服务器框架程序,创建监听套接字并接受连接请求。

1.在Chat工作区,用MFCAppWizard创建基于对话框的项目ChatServer,并在Step2中选中WindowsSocket选项。

2.添加一个从CSocket类派生的CListenSocket类,为该类添加类型为CChatServerDlg*的成员变量m_pDlg,并修改构造函数和析构函数如下:

(注意,也应修改类声明中的构造函数原型)

CListenSocket:

:

CListenSocket(CChatServerDlg*pDlg)

{

m_pDlg=pDlg;

}

CListenSocket:

:

~CListenSocket()

{

m_pDlg=NULL;

}

在类CListenSocket的头文件中,添加前置声明:

classCChatServerDlg;。

3.为CChatServerDlg类添加类型为CListenSocket*的成员变量m_pListenSocket

在类CChatServerDlg的头文件中,添加前置声明:

classCListenSocket;。

4.在CChatServerDlg类的OnInitDialog()中添加如下代码:

//TODO:

Addextrainitializationhere

m_pListenSocket=newCListenSocket(this);

if(!

m_pListenSocket->Create(8000))

{

deletem_pListenSocket;

m_pListenSocket=NULL;

AfxMessageBox("创建套接字错误!

");

returnFALSE;

}

if(!

m_pListenSocket->Listen())

{

deletem_pListenSocket;

m_pListenSocket=NULL;

AfxMessageBox("启动监听错误!

");

returnFALSE;

}

在CChatServerDlg类的实现文件中,包含CListenSocket类的头文件,即:

#include"ListenSocket.h"。

5.给项目添加CClientSocket类,该类从CSocket类派生,用于服务器和客户机进行消息传输。

给该类添加类型为CChatServerDlg*的成员变量m_pDlg,并修改构造函数和析构函数如下:

(注意,也应修改类声明中的构造函数原型)

CClientSocket:

:

CClientSocket(CChatServerDlg*pDlg)

{

m_pDlg=pDlg;

}

CClientSocket:

:

~CClientSocket()

{

m_pDlg=NULL;

}

在类CClientSocket的头文件中,添加前置声明:

classCChatServerDlg;。

6.为CChatServerDlg类添加类型为CClientSocket*的成员变量m_pClientSocket

在类CChatServerDlg的头文件中,添加前置声明:

classCClientSocket;。

7.为CChatServerDlg类添加成员函数voidOnAccept(void),并添加如下代码:

CClientSocket*pSocket=newCClientSocket(this);

m_pListenSocket->Accept(*pSocket);

在CChatServerDlg类的实现文件中,包含CClientSocket类的头文件,即:

#include"ClientSocket.h"

8.为CListenSocket类添加虚函数OnAccept(),并添加如下代码:

CSocket:

:

OnAccept(nErrorCode);

m_pDlg->OnAccept();

在CListenSocket类的实现文件中,包含CChatServerDlg类的头文件,即:

#include"ChatServerDlg.h"

编译项目,并运行服务器和客户机,试一试客户机是否能够连接服务器。

任务3:

定义消息格式、消息类型,实现用户的登录。

图1客户机/服务器之间的消息传输顺序图

表1消息格式

序号

字段名

类型

长度

说明

1

type

整型

4字节

消息的类型

2

username

字符串

20字节

用户名

3

data

字符串

256字节

数据,如文字消息

表2消息类型

序号

种类

说明

1

LOGIN_REQUEST

登录请求消息

2

LOGIN_SUCCESS

登录成功消息

3

LOGIN_FAILED

登录失败消息

4

LOGOUT_REQUEST

注销消息

5

ADD_USER

增加用户消息

6

REMOVE_USER

删除用户消息

7

PRIVATE_MESSAGE

私聊消息

8

PUBLIC_MESSAGE

群聊消息

连接并登录服务器的顺序图大致如下:

实现过程:

一、客户端

1.在客户端的对话框类CChatClientDlg的头文件中添加如下代码:

enumPROTO_TYPE//消息类型定义

{

LOGIN_REQUEST,

LOGIN_SUCCESS,

LOGIN_FAILED,

LOGOUT_REQUEST,

ADD_USER,

REMOVE_USER,

PRIVATE_CHAT,

PUBLIC_CHAT

};

typedefstructtagPacket//数据包格式定义

{

PROTO_TYPEtype;

charusername[20];

chardata[256];

}Packet;

2.在CChatClientDlg:

:

OnButtonLogin()中的caseIDOK:

下添加如下代码:

(创建套接字,并连接服务器。

连接成功后创建登录数据包并发送至服务器)

caseIDOK:

m_pMySocket=newCMySocket(this);

if(!

m_pMySocket->Create())

{

deletem_pMySocket;

m_pMySocket=NULL;

AfxMessageBox("创建套接字失败!

");

return;

}

if(!

m_pMySocket->Connect(dlg.m_strIP,dlg.m_nPort))

{

deletem_pMySocket;

m_pMySocket=NULL;

AfxMessageBox("连接服务器失败!

");

return;

}

//连接成功后发送登录数据包至服务器

Packetpacket;

memset(&packet,0,sizeof(Packet));

packet.type=LOGIN_REQUEST;

strcpy(packet.username,dlg.m_strUserName);

strcpy(packet.data,dlg.m_strPassword);

m_pMySocket->Send(&packet,sizeof(Packet));

break;

3.在CChatClientDlg类中添加voidOnReceive(void)函数,接收服务器发送的数据包,并根据数据包类型(在这里是登录成功数据包)进行相应处理。

Packetpacket;

memset(&packet,0,sizeof(Packet));

m_pMySocket->Receive(&packet,sizeof(Packet));

switch(packet.type)

{

caseLOGIN_SUCCESS:

m_listMessage.AddString("loginsucceed.");

((CButton*)GetDlgItem(IDC_BUTTON_LOGOUT))->EnableWindow(TRUE);

((CButton*)GetDlgItem(IDC_BUTTON_LOGIN))->EnableWindow(FALSE);

((CEdit*)GetDlgItem(IDC_EDIT_MESSAGE))->EnableWindow(TRUE);

break;

}

4.在CMySocket类中重载OnReceive()函数,并添加如下代码:

(当套接字收到数据包时,MFC框架会调用该函数,而该函数在内部调用对话框的OnReceive()函数对接收的数据包进行相应的处理)

CSocket:

:

OnReceive(nErrorCode);

m_pDlg->OnReceive();

在CMySocket类的实现文件中,包含CChatClientDlg类的头文件,即:

#include"ChatClientDlg.h"

5.在服务器端的CChatServerDlg类的头文件的开头添加如下的结构体,用于保存在线用户的名称和对应的套接字指针,以实现一对一的聊天消息的转发:

typedefstructtagUserInfo

{

char*username;

CClientSocket*pSocket;

}UserInfo;

在CChatServerDlg类的头文件中,添加前置声明:

classCClientSocket;。

二、服务器端

1.在服务器端的对话框类CChatServerDlg的头文件中添加如下代码:

enumPROTO_TYPE//消息类型定义

{

LOGIN_REQUEST,

LOGIN_SUCCESS,

LOGIN_FAILED,

LOGOUT_REQUEST,

ADD_USER,

REMOVE_USER,

PRIVATE_CHAT,

PUBLIC_CHAT

};

typedefstructtagPacket//数据包格式定义

{

PROTO_TYPEtype;

charusername[20];

chardata[256];

}Packet;

2.在服务器端的CChatServerDlg类中添加类型为CPtrList类型的成员变量m_listUser,当用户登录服务器之后,在该链表中添加用户的信息(指向UserInfo结构体类型的指针)。

3.在重载CListenSocket类的OnAccept()函数,并添加如下代码:

(前面已经做了)

CSocket:

:

OnAccept(nErrorCode);

m_pDlg->OnAccept();

4.在CChatServerDlg类中添加voidOnAccept(void)函数,在该函数中服务器接收客户端的连接请求,生成该用户的UserInfo结构信息,并把该信息添加到m_listUser链表中,具体代码如下:

CClientSocket*pSocket=newCClientSocket(this);

m_pListenSocket->Accept(*pSocket);

UserInfo*pUserInfo=newUserInfo();

pUserInfo->pSocket=pSocket;

m_listUser.AddHead(pUserInfo);

5.在CClientSocket类中重载OnReceive()函数,并在该函数中调用CChatServerDlg类的OnReceive()函数,代码如下:

CSocket:

:

OnReceive(nErrorCode);

m_pDlg->OnReceive();

在CClientSocket类的实现文件中,包含CChatServerDlg类的头文件,即:

#include"ChatServerDlg.h"

6.在CChatServerDlg类中添加voidOnReceive(void)成员函数,在该函数中服务器接收客户端发送的数据包并根据数据包的类型进行相应处理(在这里是处理登录请求),其代码如下:

Packetpacket;

memset(&packet,0,sizeof(Packet));

pSocket->Receive(&packet,sizeof(Packet));

switch(packet.type)

{

caseLOGIN_REQUEST:

POSITIONpos;

for(pos=m_listUser.GetHeadPosition();pos!

=NULL;)

{

UserInfo*pInfo=(UserInfo*)m_listUser.GetNext(pos);

if(pInfo->pSocket==pSocket)

{

pInfo->username=packet.username;

packet.type=LOGIN_SUCCESS;

pSocket->Send(&packet,sizeof(Packet));

break;

}

}

break;

}

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

当前位置:首页 > 自然科学

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

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