基于TCP协议的网络聊天室系统
利用这两个类设计一个网络聊天室系统。系统分为客户端和服务器端两个模块,下面分别介绍其实现过程。
1.客户端模块实现过程如下:
例如,使用CSocket类设计网络聊天室系统客户端
(1)创建一个基于对话框的工程,工程名称为“Client”。设计对话框资源如图1所示。
.jpg)
图1 客户端资源设计窗口
(2)在应用程序的InitInstance方法中初始化套接字。
WSADATA wsd; //定义WSADATA对象
WSAStartup(MAKEWORD(2,2),&wsd); //初始化套接字
(3)从CSocket类派生一个子类CClientSocket,在该类中添加m_pDialog成员。
CClientDlg *m_pDialog; //添加成员变量
(4)在CClientSocket中添加SetDialog方法,用于设置成员变量。
void CClientSocket::SetDialog(CClientDlg *pDialog)
{
m_pDialog = pDialog; //设置成员变量
}
(5)改写CClientSocket类的OnReceive方法,在套接字有数据接收时调用该方法。
void CClientSocket::OnReceive(int nErrorCode)
{
CSocket::OnReceive(nErrorCode);
if (m_pDialog != NULL) //判断成员变量是否为空
m_pDialog->ReceiveText(); //调用对话框类的ReceiveText方法接收数据
}
(6)在对话框类中添加如下成员变量。
CClientSocket m_SockClient; //定义套接字成员变量
CString m_Name; //定义一个字符串变量
(7)向对话框类中添加ReceiveText方法接收数据。
void CClientDlg::ReceiveText()
{
char buffer[BUFFERSIZE]; //定义接收数据的缓冲区
int len = m_SockClient.Receive(buffer,BUFFERSIZE); //开始接收数据
if (len != -1) //判断是否接收到数据
{
buffer[len] = ' '; //设置结束标记
m_List.AddString(buffer); //向列表中添加接收到的信息
}
}
(8)在对话框初始化时创建套接字。
m_SockClient.Create(); //创建套接字
m_SockClient.SetDialog(this); //设置套接字的成员变量
(9)处理登录按钮的单击事件,开始登录服务器。
void CClientDlg::OnLogin()
{
CString strIP,strPort; //定义两个字符串变量
UINT port ; //定义一个整数端口变量
m_ServerIP.GetWindowText(strIP); //获取服务器IP
m_NickName.GetWindowText(m_Name); //获取用户昵称
m_ServerPort.GetWindowText(strPort); //获取端口
//判断服务器IP、端口号和用户昵称是否为空
if (strIP.IsEmpty() || strPort.IsEmpty() || m_Name.IsEmpty())
{
MessageBox("请设置服务器信息","提示"); //显示提示对话框
return;
}
port = atoi(strPort); //将端口字符串传唤为整数
if (m_SockClient.Connect(strIP,port)) //开始连接服务器
{
MessageBox("连接服务器成功!","提示"); //弹出提示信息
CString str; //定义字符串变量
str.Format("%s----->%s",m_Name,"进入聊天室"); //设置输出信息
m_SockClient.Send(str.GetBuffer(0),str.GetLength());//向服务器发送数据,再由服务器转发
}
else
{
MessageBox("连接服务器失败!","提示"); //显示提示对话框
}
}
(10)处理“发送”按钮的单击事件,向服务器发送数据,再由服务器转发这些数据。
void CClientDlg::OnSendText()
{
CString strText,strInfo; //定义两个字符串变量
m_Text.GetWindowText(strText); //获取发送的内容
if (!strText.IsEmpty() && !m_Name.IsEmpty()) //判断发送信息和昵称是否为空
{
strInfo.Format("%s说: %s",m_Name,strText); //设置发送的文本
//开始发送数据
int len = m_SockClient.Send(strInfo.GetBuffer(strInfo.GetLength()),strInfo.GetLength());
}
}
(11)运行程序,效果如图2、图3所示。
.jpg)
图2 客户端窗口1
.jpg)
图3 客户端窗口2
2.服务器端模块实现过程如下:
例如,使用CSocket类设计网络聊天室系统服务器端
(1)创建一个基于对话框的应用程序,工程名称为“Server”。设置对话框资源窗口如图4所示。
.jpg)
图4 服务器端设置窗口
(2)在应用程序的InitInstance方法中初始化套接字。
WSADATA wsd; //定义WSADATA对象
AfxSocketInit(&wsd); //初始化套接字
(3)从CSocket类派生一个子类CServerSocket,在该类中定义成员变量m_pDlg。
CServerDlg* m_pDlg;
(4)向CServerSocket类中添加SetDialog函数,为m_pDlg成员变量赋值。
void CServerSocket::SetDialog(CServerDlg* pDialog)
{
m_pDlg = pDialog; //为成员变量赋值
}
(5)改写CServerSocket类的OnAccept虚方法,在套接字中有连接请求时接收其连接。
void CServerSocket::OnAccept(int nErrorCode)
{
CSocket::OnAccept(nErrorCode);
if (m_pDlg) //判断m_pDlg是否为空
m_pDlg->AcceptConnect(); //调用主对话框的AcceptConnect方法
}
(6)从CSocket类再次派生一个新类CClientSocket,在该类中定义成员变量m_pDlg。
CServerDlg* m_pDlg;
(7)向CClientSocket类中添加SetDialog函数,为m_pDlg成员变量赋值。
void CClientSocket::SetDialog(CServerDlg* pDialog)
{
m_pDlg = pDialog; //为成员变量赋值
}
(8)改写CClientSocket类的OnReceive方法,在套接字有数据接收时接收数据。
void CClientSocket::OnReceive(int nErrorCode)
{
CSocket::OnReceive(nErrorCode);
if(m_pDlg) //判断对话框是否为空
{
m_pDlg->ReceiveData(*this); //调用对话框类的ReceiveData方法
}
}
(9)在对话框类中添加如下成员变量。
CPtrList m_socketlist; //定义套接字列表容器
CServerSocket m_ServerSock; //定义套接字
(10)向对话框类中添加AcceptConnect方法,接收客户端的连接。
void CServerDlg::AcceptConnect()
{
CClientSocket* psocket = new CClientSocket(); //创建一个套接字
psocket->SetDialog(this); //设置套接字的成员变量
if (m_ServerSock.Accept(*psocket)) //接收套接字连接
m_socketlist.AddTail(psocket); //将套接字添加到列表容器中
else
delete psocket; //连接失败,释放套接字
}
(11)向对话框类中添加ReceiveData方法,用于接收套接字数据。
void CServerDlg::ReceiveData(CSocket &socket)
{
char bufferdata[BUFFERSIZE]; //定义数据缓冲区
int len = socket.Receive(bufferdata,BUFFERSIZE); //开始接收数据
if (len != -1) //判断是否接收到数据
{
bufferdata[len] = 0; //设置数据结束标记
POSITION pos = m_socketlist.GetHeadPosition(); //获取容器列表的首位置
while (pos != NULL) //遍历容器列表
{
//获取容器类表中的指定套接字
CClientSocket* socket = (CClientSocket*)m_socketlist.GetNext(pos);
if (socket != NULL) //判断套接字是否为空
socket->Send(bufferdata,len); //向套接字发送数据
}
}
}
(12)处理“设置”按钮的单击事件,创建并开始监听套接字。
void CServerDlg::OnConfig()
{
m_ServerSock.SetDialog(this); //设置套接字成员变量
CString strPort,strIP; //定义两个字符串变量
m_ServerPort.GetWindowText(strPort); //获取端口字符串
m_ServerIP.GetWindowText(strIP); //获取服务器IP
if (!strPort.IsEmpty() && !strIP.IsEmpty()) //判断端口和IP是否为空
{
UINT port = atoi(strPort); //将端口转换为整数值
m_ServerSock.Create(port,SOCK_STREAM,strIP); //创建套接字
BOOL ret = m_ServerSock.Listen(); //将套接字置于监听模式
if (ret)
MessageBox("设置成功!","提示"); //弹出提示对话框
}
}
(13)运行程序,效果如图5所示。
.jpg)
图5 服务器窗口