基于CSocket网络聊天室程序
项目介绍
- 通过CSocket类提供的功能来实现多人聊天
- 从CSocket派生出两个类:ClistenSocket和CclientSocket,它们分别用来侦听客户的连接请求和建立与客户的连接
- 服务器只需要——个侦听套接字ClistenSocket,然后根据客户的连接请求动态创建客户套接字CclientSocket
- 基于TCP网络,客户端与服务器完成信息交互
服务器端代码实现
首先新建对话框工程
添加IP控件变量m_ip,编辑控件变量m_nServPort,修改按钮为启动服务器。新建一个类CSeverScoket,基类为CSocket,进入重写页面在重写虚函数OnAccept代码如下:
void CServerSocket::OnAccept(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类
CClientSocket*psocket = new CClientSocket();
if(Accept(*psocket))
m_socketlist.AddTail(psocket);
else
delete psocket;
CSocket::OnAccept(nErrorCode);
}
代码中CClientSocket类也是基类为CSocket的新增类;
继续为类CSeverScoket增加成员函数SendAll,用于给各个客户端发消息。代码如下:
void CServerSocket::SendALL(char *bufferdata, int len)
{
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);
}
}
}
m_socketlist是CServerSocket的成员函数CPtrList m_socketlist;
继续为类CSeverScoket增加成员函数DelAll,代码如下:`
void CServerSocket::DelAll()
{
POSITION pos = m_socketlist.GetHeadPosition();
while(pos !=NULL)
{
CClientSocket*socket = (CClientSocket*)m_socketlist.GetNext(pos);
if(socket != NULL)
delete socket;
}
m_socketlist.RemoveAll();
}
接下来为CClientSocket类添加代码,用于和客户端信息交互,首先接收信息重写虚函数OnReceive,代码如下:
void CClientSocket::OnReceive(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类
char bufferdata [2048];
int len =Receive (bufferdata,2048);
bufferdata[len] = '\0';
theApp.m_ServerSock.SendALL (bufferdata,len);
CSocket::OnReceive(nErrorCode);
}
socket对象的作用域在App类中,在App类中加入socket库的初始化
BOOL CServerApp::InitInstance()
{
WSADATA wsd;
AfxSocketInit(&wsd);
最后给启动服务器添加消息处理函数
void CServerDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData ();
CString strIP;
BYTE nf1,nf2,nf3,nf4;
m_IP.GetAddress(nf1,nf2,nf3,nf4);
strIP.Format(_T("%d.%d.%d.%d"),nf1,nf2,nf3,nf4);
if(m_nServPort>1024 && !strIP.IsEmpty ())
{
theApp.m_ServerSock.Create(m_nServPort,SOCK_STREAM,strIP);
BOOL ret = theApp.m_ServerSock.Listen (); //开始监听
if (ret)
AfxMessageBox(_T("启动成功"));
}
else
AfxMessageBox(_T("信息设置错误"));
CDialogEx::OnOK();
}
再添加摧毁事件处理函数
void CServerDlg::OnDestroy()
{
CDialogEx::OnDestroy();
theApp.m_ServerSock.DelAll();
}
这样服务端就完成了,输入正确的IP地址和端口号就可以使用了端口号要大于1024!
客户器端代码实现
新建两个对话框登录服务器对话框和聊天对话框:
同样先进行套接字库初始化与上文一样;登录对话框首先连接服务器,登录代码如下:
void CclientDlg::OnBnClickedOk() //denglu
{
// TODO: 在此添加控件通知处理程序代码
CString strIP,strPort;
UINT port;
UpdateData ();
if(m_IP.IsBlank () ||m_nServPort <1024||m_strNickname.IsEmpty())
{
AfxMessageBox (_T("请设置服务器信息"));
return;
}
BYTE nf1,nf2,nf3,nf4;
m_IP.GetAddress (nf1,nf2,nf3,nf4);
strIP.Format(_T("%d.%d.%d.%d"),nf1,nf2,nf3,nf4);
theApp.m_strName = m_strNickname;
if (theApp.m_clientsock.Connect (strIP ,m_nServPort ))
{
AfxMessageBox (_T("连接服务器成功"));
ChatDlg dlg;
theApp.m_clientsock.SetWnd(&dlg);
dlg.DoModal();
}
else
{
AfxMessageBox (_T("连接服务器失败"));
}
}
// CClientSocket 成员函数 消息传递
void CClientSocket ::SetWnd( ChatDlg *pDlg)
{
m_pDlg = pDlg;
}
ClientSocket m_clientsock为Client的成员变量
同样添加类ClientSocket,重载虚函数OnReceive,用于接收服务器端发来的消息,代码如下:
oid CClientSocket::OnReceive(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类
if (m_pDlg)
{
char buffer[2048];
CString str;
int len=Receive(buffer,2048);
if(len != -1)
{
buffer[len] ='\0';
buffer[len+1]='\0';
str.Format (_T("%s"),buffer);
m_pDlg->m_list.InsertString(i,str);
m_pDlg-> GetDlgItem(IDC_EDIT1)->SetWindowText(_T(""));
}
}
i++;
CSocket::OnReceive(nErrorCode);
}
切换资源视图在聊天对话框中添加发送按钮的消息处理函数
void CclientDlg::OnBnClickedOk() //denglu
{
// TODO: 在此添加控件通知处理程序代码
CString strIP,strPort;
UINT port;
UpdateData ();
if(m_IP.IsBlank () ||m_nServPort <1024||m_strNickname.IsEmpty())
{
AfxMessageBox (_T("请设置服务器信息"));
return;
}
BYTE nf1,nf2,nf3,nf4;
m_IP.GetAddress (nf1,nf2,nf3,nf4);
strIP.Format(_T("%d.%d.%d.%d"),nf1,nf2,nf3,nf4);
theApp.m_strName = m_strNickname;
if (theApp.m_clientsock.Connect (strIP ,m_nServPort ))
{
AfxMessageBox (_T("连接服务器成功"));
ChatDlg dlg;
theApp.m_clientsock.SetWnd(&dlg);
dlg.DoModal();
}
else
{
AfxMessageBox (_T("连接服务器失败"));
}
}
最后我们运行一下就可以了
源码下载
https://download.csdn.net/download/weixin_51071767/21979551?spm=1001.2014.3001.5503