看完这篇文章,你会学会CSocket类的网络编程
先看项目截图
我先给大家推荐一个图标网站:iconfont
https://www.iconfont.cn/
里面有很多免费的图标
正文
CSocket类我们通常不直接使用它,而是通过类继承派生出我们自己的类,CSocket是阻塞模式。
我们采用C/S模式啊,就是一个服务器,多个客服端。
服务器的网络通信流程:
Create()->Listen()->Send()/Receive()->Receive()/Send()
客服端的网络通信流程:
Create()->Connect->Send()/Receive()->Receive()/Send()
我们先打开VS2019,新建一个MFC对话框项目,项目名叫ChatClient
作为客服端
新建一个对话框,并添加类:CDlgLogin,对话框布局就是上面的登录窗口。
添加相关的控件变量:
//DlgLogin.h
CString m_Name;//昵称
CString m_Ip;//IP地址
INT m_Port;//端口号
双击“登录”按钮,在响应函数中写入相关代码
//DlgLogin.cpp
EndDialog(IDOK);//关闭对话框
UpdateData();//更新数据
CChatClientDlg dlg;
dlg.DoModal();//弹出对话框
有人会问,你那个对话框怎么有背景图案呢?
打开CDlgLogin类的类向导,添加WM_PAINT消息响应函数OnPaint()
并输入代码
CRect Rect;
GetClientRect(&Rect);
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
BITMAP logbmp;
bmp.GetBitmap(&logbmp);
CDC memDC;
memDC.CreateCompatibleDC(&dc);
memDC.SelectObject(&bmp);
dc.SetStretchBltMode(HALFTONE);
dc.StretchBlt(0, 0, Rect.Width(), Rect.Height(), &memDC, 0, 0, logbmp.bmWidth, logbmp.bmHeight, SRCCOPY);
图片我就不发出来了,你们可以自己找一个位图
我们添加一个类:CClientSocket
基类为CSocket
在它的构造函数中写入代码:
CClientSocket(CChatClientDlg*dlg);
CClientSocket::CClientSocket(CChatClientDlg* dlg)
{
m_Maindlg = dlg;
}
传入一个CChatClientDlg的指针,好方便我们对控件的编辑
并在ClientSocket.h中写入代码
#include "ChatClientDlg.h"
class CChatClientDlg;//类的前置声明
CChatClientDlg* m_Maindlg;
在ChatClientDlg.cpp中的OnInitDialog()写入代码
CString strError;
m_pSocket = new CClientSocket(this);
m_LoginDlg = (CDlgLogin*)AfxGetMainWnd();
if (FALSE == m_pSocket->Create())
{
strError.Format(L"创建套接字失败,错误代码:%d", GetLastError());
MessageBox(strError, L"错误", MB_ICONERROR | MB_OK);
delete m_pSocket;
m_pSocket = NULL;
EndDialog(IDOK);
return TRUE;
}
CString strIp;//IP地址
UINT m_Port;//端口号
strIp = m_LoginDlg->m_Ip;
m_Port = m_LoginDlg->m_Port;
if (FALSE == m_pSocket->Connect(strIp,m_Port))
{
strError.Format(L"连接服务器失败,错误代码:%d", GetLastError());
MessageBox(strError, L"错误", MB_ICONERROR | MB_OK);
delete m_pSocket;
m_pSocket = NULL;
EndDialog(IDOK);
return TRUE;
}
//发送进入聊天室消息
CString strSendName;
CString strMsg;
strSendName = m_LoginDlg->m_Name;
strMsg.Format(L"%s 已进入聊天室\r\n", strSendName);
m_pSocket->Send(strMsg, strMsg.GetLength() * 2);
在ChatClientDlg.h添加变量
class CClientSocket;//类的前置声明
class CDlgLogin;//类的前置声明
CDlgLogin* m_LoginDlg;
CClientSocket* m_pSocket;
为那两个CEdit控件添加变量
CEdit m_Message;
CString m_Send;
在发送按钮的响应函数中添加代码
UpdateData(); //更新数据
CString strSend; //待发送的消息
CString strName; //昵称
strName = m_LoginDlg->m_Name;
if (m_Send.GetLength() > 50)
{
MessageBox(L"您发送的内容太多", L"错误", MB_ICONERROR | MB_OK);
return;
}
strSend.Format(L"%s : %s\r\n",strName, m_Send);
m_pSocket->Send(strSend, strSend.GetLength() * 2);
在ClientSocket.cpp重载OnReceive虚函数
void CClientSocket::OnReceive(int nErrorCode)
{
TCHAR* pbuffer = new TCHAR[1024];
ZeroMemory(pbuffer, sizeof(TCHAR) * 1024);
Receive(pbuffer, sizeof(TCHAR) * 1024);
int size = m_Maindlg->m_Message.GetWindowTextLength();
m_Maindlg->m_Message.SetSel(size, -1);
m_Maindlg->m_Message.ReplaceSel(pbuffer);
delete[]pbuffer;
CSocket::OnReceive(nErrorCode);
}
客服端写完了,来写服务端
“开启服务器”按钮的响应函数:
void CChatServerDlg::OnBnClickedButton1()
{
UpdateData();
CString str;
m_Socket = new CListenSocket;
if (m_Ip.IsEmpty() || m_Port <= 1024)
{
MessageBox(L"请输入正确的IP地址和端口号", L"错误", MB_OK | MB_ICONERROR);
return;
}
if (FALSE==m_Socket->Create(m_Port, SOCK_STREAM, m_Ip))
{
str.Format(L"创建套接字失败,错误代码:%d", GetLastError());
MessageBox(str, L"错误", MB_OK | MB_ICONERROR);
delete m_Socket;
m_Socket = NULL;
return;
}
if (FALSE == m_Socket->Listen())
{
str.Format(L"监听失败,错误代码:%d", GetLastError());
MessageBox(str, L"错误", MB_OK | MB_ICONERROR);
delete m_Socket;
m_Socket = NULL;
return;
}
GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
}
相应的变量
CListenSocket* m_Socket;
CString m_Ip;
INT m_Port;
服务器我们添加了两个CSocket派生类:CListenSocket、CClientSocket
“关闭服务器”按钮:
if (m_Socket != NULL)
{
m_Socket->Close();
KillTimer(1);
}
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);
并在ChatServerDlg.cpp中写入
extern list<CClientSocket*>m_pClientsocket;
在CListenSocket.cpp中写入
#include "pch.h"
#include "ListenSocket.h"
#include "ClientSocket.h"
list<CClientSocket*>m_pClientsocket;
void CListenSocket::OnAccept(int nErrorCode)
{
CClientSocket* m_psocket=new CClientSocket;
Accept(*m_psocket);
m_pClientsocket.push_back(m_psocket);
CSocket::OnAccept(nErrorCode);
}
在CClientSocket.cpp中写入
#include "pch.h"
#include "ClientSocket.h"
extern list<CClientSocket*>m_pClientsocket;
void CClientSocket::OnReceive(int nErrorCode)
{
TCHAR* pbuffer = new TCHAR[1024];
ZeroMemory(pbuffer, sizeof(TCHAR) * 1024);
Receive(pbuffer, sizeof(TCHAR) * 1024);//接收到的数据
list<CClientSocket*>::iterator it;
for (it = m_pClientsocket.begin(); it != m_pClientsocket.end(); it++)
{
CString strMsg; //发送的消息
CTime m_Time; //时间
CString strTime;
CClientSocket* pSocket = *it;
CString strIpAddress; //IP地址
UINT uPort; //端口号
m_Time = CTime::GetTickCount();
strTime = m_Time.Format(L"%H:%M:%S");
pSocket->GetPeerName(strIpAddress, uPort);
strMsg.Format(L"[%s] %s",strTime, pbuffer);
pSocket->Send(strMsg, strMsg.GetLength() * 2);
}
delete[] pbuffer;
CSocket::OnReceive(nErrorCode);
}
好了,完了
我给一个软件链接
https://fow.lanzoui.com/b02cdqbsd
密码:eh6x