目录
1.1客户端/服务端界面设计
客户端
利用亿图图示,画出要实现的客户端界面样式
在强大的艺术细胞加持下😊,我们的聊天软件界面也有了雏形!
客户端MFC布局
编译结果
服务端
服务端MFC布局
编译结果
1.2IP和端口获取
客户端
获取IP和端口
#include<atlbase.h>
void CMFCChatClientDlg::OnBnClickedConnectBtn()
{
CString strPort, strIP;
//获取控件里面内容
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
GetDlgItem(IDC_IPADDRESS)->GetWindowText(strIP);
//CString 转char*
USES_CONVERSION;
LPCSTR szPort = (LPCSTR)T2A(strPort);
LPCSTR szIP = (LPCSTR)T2A(strIP);
TRACE("szPort=%s,szIP=%s", szPort, szIP);
}
服务端
获取端口
#include<atlbase.h>
void CMFCChartServerDlg::OnBnClickedStartBtn()
{
TRACE("OnBnClickedStartBtn");
CString strPort;
//获取控件里面内容
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
//CString 转char*
USES_CONVERSION;
LPCSTR szPort = (LPCSTR)T2A(strPort);
TRACE("szPort=%s", szPort);
}
1.3重写socket,连接服务端与客户端
最终效果
客户端
获取IP和端口,创建Socket (重写OnConnect和OnReceive),调用Connect连接
服务端
获取端口,创建Socket(重写OnAccept),开始监听;每次与客户端连接后再创建一个Socket(重写OnReceive)
客户端
继承CAsyncSocket类,并重写OnConnect( )和onReceive
#pragma once
#include<afxsock.h>
class CMySocket :
public CAsyncSocket
{
public:
CMySocket();
virtual ~CMySocket();
//重写Connect函数
virtual void OnConnect(int nErrorCode);
//重写Receive函数
virtual void onReceive(int nErrorCode);
};
重写函数实现
void CMySocket::OnConnect(int nErrorCode)
{
TRACE("############OnConnect");
//获取主窗口
CMFCChatClientDlg* dlg = (CMFCChatClientDlg*)AfxGetApp()->GetMainWnd();
CString str;
//获取系统当前时间
dlg->m_tm = CTime::GetCurrentTime();
//死背吧
str = dlg->m_tm.Format("%X");
str += _T("与服务器连接成功");
//将时间在历史消息中显示
dlg->m_list.AddString(str);
//标准写法
CAsyncSocket::OnConnect(nErrorCode);
}
void CMySocket::OnReceive(int nErrorCode)
{
TRACE("############onReceive");
}
在客户端“连接”控件函数里
获取端口和IP,创建一个Socket对象,创建一个Socket,然后进行连接
void CMFCChatClientDlg::OnBnClickedConnectBtn()
{
//拿到端口和IP
CString strPort, strIP;
//获取控件里面内容
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
GetDlgItem(IDC_IPADDRESS)->GetWindowText(strIP);
//CString 转char*
USES_CONVERSION;
LPCSTR szPort = (LPCSTR)T2A(strPort);
LPCSTR szIP = (LPCSTR)T2A(strIP);
TRACE("szPort=%s,szIP=%s", szPort, szIP);
//字符串转数字
int iPort = _ttoi(strPort);
//创建一个socket对象
m_client = new CMySocket;
//创建套接字
if (!m_client->Create()) {
//错误代码10093,需要在项目.cpp文件的InitInstance( )函数里调用AfcSocketInit()函数初始话
TRACE("m_client Create error %d", GetLastError());
return;
}
else {
TRACE("m_client Creat Success");
}
//连接
/*判断是否连接成功在这里是没办法判断,需要在回调函数中判断;因此如果使用
* if(!m_client->Connect(strIP,iPort))判断是否连接成功则会报出10035(WSAEWOULDBLOCK)错误
* 在这里如果想判断的话就只需要判断是否等于SOCKET_ERROR就可以了
*/
if (m_client->Connect(strIP, iPort) != SOCKET_ERROR) {
TRACE("m_client Connect errot %d", GetLastError());
}
}
服务端
CServerSocket继承CAsyncSocket类,并重写OnAccept( )函数 ——监听类
#pragma once
#include<afxsock.h>
class CServerSocket :
public CAsyncSocket
{
public:
CServerSocket();
virtual ~CServerSocket();
virtual void OnAccept(int nErrorCode);
};
重写函数实现
void CServerSocket::OnAccept(int nErrorCode)
{
TRACE("#####OnAccept");
CMFCChartServerDlg* dlg = (CMFCChartServerDlg*)AfxGetApp()->GetMainWnd();
//每次相连创建一个连接socket
dlg->m_chat = new CChatSocket;
//接收客户端连接
Accept(*(dlg->m_chat));
CString str;
dlg->m_tm = CTime::GetCurrentTime();
str = dlg->m_tm.Format("%X");
str += _T("客户端连接成功");
dlg->m_list.AddString(str);
dlg->m_list.UpdateData(FALSE);
CAsyncSocket::OnAccept(nErrorCode);
}
CChatServet继承CAsyncSocket类,并重写OnReceive( )函数 ——连接类
#pragma once
#include <afxsock.h>
class CChatSocket :
public CAsyncSocket
{
public:
CChatSocket();
virtual ~CChatSocket();
virtual void OnReceive(int nErrorCode);
};
重写函数实现
void CChatSocket::OnReceive(int nErrorCode)
{
}
在服务端“启动”控件函数里
获取端口值,创建Socket对象,创建Socket,监听
void CMFCChartServerDlg::OnBnClickedStartBtn()
{
TRACE("OnBnClickedStartBtn");
CString strPort;
//获取控件里面内容
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
//CString 转char*
USES_CONVERSION;
LPCSTR szPort = (LPCSTR)T2A(strPort);
TRACE("szPort=%s", szPort);
//创建服务器Socket的对象
m_server = new CServerSocket;
//创建Socket(套接字)
int iPort = _ttoi(strPort);
if (!m_server->Create(iPort)) {
TRACE("m_server Create errorCode=%d", GetLastError());
return;
}
//监听,当有客户端连接时回调OnAccept
if (!m_server->Listen()) {
TRACE("m_sercer listen Create errorCode=%d", GetLastError());
return;
}
CString str;
m_tm = CTime::GetCurrentTime();
str = m_tm.Format("%X");
str += _T("建立服务");
m_list.AddString(str);
//进行数据更新,FALSE把数据从控件搞下来,TRUE把数据从控件搞上去
UpdateData(FALSE);
}
1.4客户端与服务端互发消息
最终效果
服务端(客户端)
在控件函数中
发送:获取编辑框内容→调用send函数发送→在历史消息框显示信息内容→清空编辑框
在OnReceive函数中
接收:使用Receive函数获得服务端(客户端)发送内容→显示在消息列表框
客户端
发送控件函数
void CMFCChatClientDlg::OnBnClickedSendBtn()
{
TRACE("Client SEND MESG");
//1.获取编辑框内容
CString strTmpMsg;
GetDlgItem(IDC_SENDMSG_EDIT)->GetWindowText(strTmpMsg);
//转char*类型
USES_CONVERSION;
char* szSendBuf = T2A(strTmpMsg);
//2.发送给服务端,SEND_MAX_BUF(1024)是一个宏定义 ,在头文件MFCChartClient.h文件中
m_client->Send(szSendBuf, SEND_MAX_BUF, 0);
//3.显示到列表框里
CString strShow;
CString strInfo = _T("我:");
strShow = CatShowString(strInfo, strTmpMsg);
m_list.AddString(strShow);
//控件更新
UpdateData(FALSE);
//清空编辑框
GetDlgItem(IDC_SENDMSG_EDIT)->SetWindowText(_T(""));
// TODO: 在此添加控件通知处理程序代码
}
//拼接显示信息 时间+呢称+消息
CString CMFCChatClientDlg::CatShowString(CString strInfo, CString strMsg)
{
//时间+呢称+消息
CString strTime;
CTime tmNow;
tmNow = CTime::GetCurrentTime();
strTime = tmNow.Format("%X");
CString strShow;
strShow = strTime;
strShow += strInfo;
strShow += strMsg;
return strShow;
}
OnReceive函数里
void CMySocket::OnReceive(int nErrorCode)
{
//获取服务端发送内容
TRACE("############onReceive");
CMFCChatClientDlg* dlg = (CMFCChatClientDlg * )AfxGetApp()->GetMainWnd();
//SEND_MAX_BUF(1024)是一个宏定义 ,在头文件MFCChartClient.h文件中
char szRecvBuf[SEND_MAX_BUF] = { 0 };
Receive(szRecvBuf, SEND_MAX_BUF, 0);
TRACE("###########szRecvBuf=%s", szRecvBuf);
//显示在列表框
USES_CONVERSION;
CString sreRecvMsg = A2W(szRecvBuf);
CString strInfo = _T("服务端:");
CString strShow;
strShow = dlg->CatShowString(strInfo, sreRecvMsg);
dlg->m_list.AddString(strShow);
CAsyncSocket::OnReceive(nErrorCode);
}
服务端
发送控件函数
void CMFCChartServerDlg::OnBnClickedSendBtn()
{
// TODO: 在此添加控件通知处理程序代码
TRACE("###### Server Send Msg");
//获取编辑框内容
CString strTmpMsg;
GetDlgItem(IDC_SEND_EDIT)->GetWindowText(strTmpMsg);
//转char*类型
USES_CONVERSION;
char*szSendBuf = T2A(strTmpMsg);
//MAX_SERVER_BUF(1024)是一个宏定义 ,在头文件MFCChartServer.h文件中
m_chat->Send(szSendBuf, MAX_SERVER_BUF, 0);
//3.显示到列表框里
CString strInfo = _T("我:");
CString strShow;
strShow = CatShowString(strInfo, strTmpMsg);
m_list.AddString(strShow);
//控件更新
UpdateData(FALSE);
//清空编辑框
GetDlgItem(IDC_SEND_EDIT)->SetWindowText(_T(""));
// TODO: 在此添加控件通知处理程序代码
}
//拼接显示信息 时间+呢称+消息
CString CMFCChartServerDlg::CatShowString(CString strInfo, CString strMsg)
{
//时间+呢称+消息
CString strTime;
CTime tmNow;
tmNow = CTime::GetCurrentTime();
strTime = tmNow.Format("%X");
CString strShow;
strShow = strTime;
strShow += strInfo;
strShow += strMsg;
return strShow;
}
OnReceive函数
void CChatSocket::OnReceive(int nErrorCode)
{
//获取客户端发送内容
TRACE("#####Server OnReceive");
CMFCChartServerDlg* dlg = (CMFCChartServerDlg*)AfxGetApp()->GetMainWnd();
//MAX_SERVER_BUF(1024)是一个宏定义 ,在头文件MFCChartServer.h文件中
char szRecvBuf[MAX_SERVER_BUF] = {0 };
//便准写法
Receive(szRecvBuf, MAX_SERVER_BUF, 0);
TRACE("############sERVER szRecvBuf=%s", szRecvBuf);
//2.显示buf
USES_CONVERSION;
CString sreRecvMsg = A2W(szRecvBuf);
CString strInfo = _T("客户端:");
CString strShow;
strShow = dlg->CatShowString(strInfo, sreRecvMsg);
dlg->m_list.AddString(strShow);
CAsyncSocket::OnReceive(nErrorCode);
}