1, 生成的类是Dlg 在对话款中天机4个Button 4个示例编辑框 4个文本框
一个组合框(Combo box),一个列表框(List Box),反正界面刚开始要设计成这样,ID自己修改
这个项目为客户端
2在一个项目中添加一个新项目
这个新项目长这个样子
3,s双击第一个项目的连接对话框,在里面添加函数代码
void CMFCCheckClientDlg::OnBnClickedConnectBtn()
{
CString strPort, strIP;
//从空间里面过去内容
GetDlgItem(IDC_PORT_EIDT)->GetWindowText(strPort);
GetDlgItem(IDC_IPADDRESS)->GetWindowText(strIP);
//CString 转 char *
USES_CONVERSION; //一个宏
//意思就是一个CString类型的空间转换为char数据类型,(强转)转换函数
LPCSTR szPort = (LPCSTR)T2A(strPort);
LPCSTR szIP = (LPCSTR)T2A(strIP);
//打印函数
TRACE("zsPort=%s,szIP=%s", szPort, szIP);
}
想要点击生成,我们需要在前面添加两个头文件,其中任何一个头文件都可以
#include <windows.h>
#include <albase.h>
在服务端启动那里,我们也要添加湖区端口的函数
void CMFCChatServerDlg::OnBnClickedButton1()
{
CString strPort;
GetDlgItem(IDC_EDIT_ONE)->GetWindowText(strPort);
USES_CONVERSION;
LPSTR szPort = (LPSTR)T2A(strPort);
TRACE("szPort=%s", szPort);
}
3,我们需要重写我们的客户端
在Client的源文件中添加一个类,基类为雨布处理的一个API CAsyncSocket
我们的类认识不了,添加头文件 -->#include <afxsoc.h>
然后我们在这个CMySocket.h中添加函数代码
#pragma once
#include <afxsock.h>
class CMySocket :
public CAsyncSocket
{
public:
CMySocket();
virtual ~CMySocket();
virtual void OnConnect(int nErrorCode);
virtual void OnReceive(int nErrorCode);
};
在CMySocket.cpp中添加函数代码
#include "pch.h"
#include "CMySocket.h"
CMySocket::CMySocket()
{
}
CMySocket::~CMySocket()
{
}
void CMySocket::OnConnect(int nErrorCode)
{
}
void CMySocket::OnReceive(int nErrorCode)
{
}
4,因为我们添加的这个类是 MFCChatClientDlg中的类
所以我们需要在 MFCChatClientDlg中添加成员变量
在生成消息映射函数的 public变量中
添加一个指针类型的 Socket 变量
CMySocket*m_client;
这个是后我们我会发现编译器不认识这个东西我们需要在前面添加头文件
#include "CMySocket.h"
5,在头文件中定义好变量以后,我们就需要在MFCCheckClientDlg.cpp中添加函数代码
//把字符串转换为数字的函数
int iPort = _ttoi(strPort);//int 类型的变量用i开头
//创建一个一个socket对象
m_client = new CMySocket;
//创建套接字
m_client->Create();
//连接
m_client->Connect(strIP,iPort);
6,我们要将接受到的信息发送到消息记录的选框内
给这个空白的DlgClient的选框添加一个变量,名称为m_list
在MFCCheckClientDlg.h中行添加一个变量MFC的聊天软件开发
CTime m_tm;
给这个示例编辑框添加一个变量
m_input 做为我们的输入框
7,在CMYSocket.cpp中添加两个头文件
#incldue "MFCCheckClientDlg.h"
#include "MFCChecKCliet.h"
/ 回调 重写 :满座我们自己设计的特殊用途: 传参数
void CMySocket::OnConnect(int nErrorCode)
{
CMFCCheckClient*dlg=(CMFCCheckClientDlg*)AfxGetApp()-->GetMainWnd()
{
CString str;
dlg->m_tm=CTIime::GetCuurenTime();
srt=dlg->m_tm.Format("%X");
str+=_T("服务器连接成功");
dlg->m_list.AddString(str);
CAsyncSocket::OnSend(nErrorCode);
}
}
7,服务端需要重写两个类 因为有两个Socket
服务端有一个监听的Socket 与客户端有一个连接的Socket
在服务器的源文件中添加一个类
CAsyncSocket是一个强大的基类,很多类都是由它派生来
这个时候我们要重写接受函数我们在CServerSocket.h中函数重载
#pragma once
#incldue <afxsock.h>
class CServerSocket:
public CAsynSocket
{
public :
CServerSocket();
viritual ~CServerSocket();
virtual void OnAccept(int ErrorCode);
}
在CServerSocket.cpp中添加两个头文件
#include "MFCChatServerDlg.h"
#include "MFCChatServer.h"
用来认识我们下面的标准函数重载
CServerSocket::CServerSocket()
{
}
CServerSocket::~CServerSocket()
{
}
//当右人连接的时候,是要触发我啊这个回调
void CServerSocket::OnAccept(int ErrorCode)
{
//我们带你关机启动的时候,回调这个接受函数.拿到文本大窗口
CMFCChatServerDlg* dlg = (CMFCChatServerDlg*)AfxGetApp()->GetMainWnd();
}
8,要接受消息,我们需要在服务器的大文本中添加一个变量 名字要和之前的一样 m_list
9,双击服务端的启动按钮,然后添加代码
CString strPort;
//控件间中获取内容
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
//CString 转换成char
USES_CONVERSION;
LPSTR szPort = (LPSTR)T2A(strPort);
TRACE("szPort=%s", szPort);
10,在MFCChactServerDlg.h中定义一个类的对象
CServerSocket* m_server;
返回MFCChactServerDlg.cpp文件中
//每次点级启动的时候都要new 一个Server的对象
m_server = new CServerSocket;
这个时候我们的编译器不认识
我们需要添加一个头文件
#include "CServerSocket.h"
把剩下的代码添加上去
void CMFCChatServerDlg::OnBnClickedStartBtn()
{
CString strPort;
//控件间中获取内容
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
//CString 转换成char
USES_CONVERSION;
LPSTR szPort = (LPSTR)T2A(strPort);
TRACE("szPort=%s", szPort);
char iPort = _ttoi(strPort);
//每次点级启动的时候都要new 一个Server的对象
m_server = new CServerSocket;
//创建socket套接字
m_server->Create(iPort);
m_server->Listen();
}
我们还需要在
文件中添加一个这样的头文件,不然编译器不认识
11,我们在初始化的时候就将端口和IP写好
在服务器的初始化函数中 ---->OninitDialog()
添加代码 GetDlgItem(IDC_PORT_EDIT)->SetWindowText(_T("5000"));
在客户端的初始化函数中,我们同样也这样写
GetDlgItem(IDC_PORT_EIDT)->SetWindowTextW(_T("5000"));
GetDlgItem(IDC_IPADDRESS)->SetWindowTextW(_T("127.0.0.1"));
12 我们在客户端的连接函数中添加容错代码
m_client->Connect(strIP, iPort); 注意后面两个参数补上
if (!m_client->Create())
{
TRACE("m_client Create error %d", GetLastError());
return;
}
else
{
TRACE("m_client Create Success");
}
然后我们在 MFCCheckClient.cpp中添加初始化 代码
AfxSocketInit();
我们是添加这个在初始化函数的前面
服务端的这个地方也同样添加这段代码
13 我们需要在MFCChatServerDlg.h 中定义一个时间的变量
CTime m_tm;
在MFCChactServerDlg.cpp中添加代码
void CMFCChatServerDlg::OnBnClickedStartBtn()
{
CString strPort;
//控件间中获取内容
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
//CString 转换成char
USES_CONVERSION;
LPSTR szPort = (LPSTR)T2A(strPort);
TRACE("szPort=%s", szPort);
char iPort = _ttoi(strPort);
//每次点级启动的时候都要new 一个Server的对象
m_server = new CServerSocket;
//创建socket套接字 一定要加容错
if (!m_server->Create(iPort))
{
TRACE("m_server Create errorCode=%d", GetLastError());
return;
}
if(!m_server->Listen())
{
TRACE("m_serverListenrrorCode=%d", GetLastError());
return;
}
CString str;
m_tm.Format("%X");
str += _T("建立服务");
m_list.AddString(str);
UpdateData(FALSE);//FASE是将数据考下来
}
直接将原有代码覆盖
14 这个时候我们要添加一个类
在 服务器中的 CChatSocket.h中添加代码
#pragma once
#include <afxsock.h>
class CChatSocket :
public CAsyncSocket
{
public:
CChatSocket();
virtual ~CChatSocket();
virtual void OnReceive(int nErrorCode);
};
在 CChatSocket.cpp中添加代码
#include "pch.h"
#include "CChatSocket.h"
CChatSocket::CChatSocket()
{
}
CChatSocket::~CChatSocket()
{
}
void CChatSocket::OnReceive(int nErrorCode)
{
}
在ServerSocket.cpp中添加函数代码
void ServerSoocket::OnAccept(int nErrorCode)
{
CMFCChatServerDlg* dlg = (CMFCChatServerDlg*)AfxGetApp()->GetMainWnd();
}
15,我们在MFCChatSe
rverDlg.h中添加一个成员
CChatSocket *m_chat; 这个时候编译器会不认识 添加头文件就行
#include "CChatSocket.h"
然后在这个函数下面添加代码
void ServerSoocket::OnAccept(int nErrorCode)
{
CMFCChatServerDlg* dlg = (CMFCChatServerDlg*)AfxGetApp()->GetMainWnd();
dlg->m_chat = new CChatSocket;
Accept(*(dlg->m_chat));
CString str;
dlg->m_tm = CTime::GetCurrentTime();
dlg->m_tm.Format("%X");
str += _T("连接天地宇宙客户端成功");
dlg->m_list.AddString(str);
dlg->m_list.UpdateData(FALSE);
CAsyncSocket::OnAccept(nErrorCode);
}
这个时候,我们会发现时间没有显示出来
void CMFCChatServerDlg::OnBnClickedStartBtn()
{
//将CString 转换为 char*型
CString strPort;
GetDlgItem(IDC_PORT_EDIT)->GetWindowText(strPort);
USES_CONVERSION;
LPSTR szPort = (LPSTR)T2A(strPort);
TRACE("szPort=%s", szPort);
int iPort = _ttoi(strPort);
m_server = new ServerSoocket;
if (!m_server->Create(iPort))
{
TRACE("m_server Create errorCode=%d", GetLastError());
return;
}
if (!m_server->Listen())
{
TRACE("m_server Listen errorCode=%d", GetLastError());
return;
}
CString str;
m_tm = CTime::GetCurrentTime();
str=m_tm.Format("%X");
str += _T("创建天地宇宙客户成功");
m_list.AddString(str);
UpdateData(FALSE);
}
str=m_tm.Format("%X");关键点在于我们之前没有将("%X")付给str;
16,我们不难发现,有一个1003的错误,我们只是需要在MFCChactClientDlgDlg.cpp
判断连接端口和IP的函数改一下
if (m_client->Connect(strIP, iPort) != SOCKET_ERROR)
{
TRACE("m_client Connect error %d", GetLastError());
return;
}
17,这个时候我们连接已经好了,我们需要了,
双击客户端的发送按钮
客户端要发送消息,在发送消息函数里面添加函数代码
void CMFCChactClientDlgDlg::OnBnClickedSendBtn()
{
//获取编辑框内容
CString strTmpMsg;
GetDlgItem(IDC_SENDMSG_EDIT)->GetWindowText(strTmpMsg);
USES_CONVERSION;
char* szSendBuf = T2A(strTmpMsg);
//发送给服务端
m_client->Send(szSendBuf, 200, 0);//200个字节
//显示到列表框
CString strShow=_T("我:");
CString strTime;
m_tm = CTime::GetCurrentTime();
strTime = m_tm.Format("%X");
strShow = strTime + strShow;
strShow += strTmpMsg;
m_list.AddString(strShow);
UpdateData(FALSE);
}
18,在CChatSocket.cpp中添加头文件
#include "MFCChatServer.h"//这个头文件
#include "ServerSoocket.h"
#include "MFCChatServerDlg.h"
添加函数代码
void CChatSocket::OnReceive(int nErrorCode)
{
//1,接受数据到Buf
CMFCChatServerDlg* dlg = (CMFCChatServerDlg*)AfxGetApp()->GetMainWnd();
char szRecvBuf[200] = { 0 };
Receive(szRecvBuf, 200, 0);//200个字节
USES_CONVERSION;
CString strRecvMsg = A2W(szRecvBuf);
CString strShow = _T("客户端:");
CString strTime;
dlg->m_tm = CTime::GetCurrentTime();
strTime = dlg->m_tm.Format("%X");
strShow = strTime + strShow;
strShow += strRecvMsg;
dlg->m_list.AddString(strShow);
CAsyncSocket::OnReceive(nErrorCode);
}
19,在服务端里贴接受函数代码
void CMySocket::OnReceive(int nErrorCode)
{
//1,接受数据到Buf
CMFCChactClientDlgDlg* dlg = (CMFCChactClientDlgDlg*)AfxGetApp()->GetMainWnd();
char szRecvBuf[200] = { 0 };
Receive(szRecvBuf, 200, 0);//200个字节
USES_CONVERSION;
CString strRecvMsg = A2W(szRecvBuf);
CString strShow = _T("服务端:");
CString strTime;
dlg->m_tm = CTime::GetCurrentTime();
strTime = dlg->m_tm.Format("%X");
strShow = strTime + strShow;
strShow += strRecvMsg;
dlg->m_list.AddString(strShow);
dlg->m_list.UpdateData(FALSE);
CAsyncSocket::OnReceive(nErrorCode);
}
20,双击服务端的发送函数
void CMFCChatServerDlg::OnBnClickedSendBtn()
{
//获取编辑框内容
CString strTmpMsg;
GetDlgItem(IDC_SEND_EDIT)->GetWindowText(strTmpMsg);
USES_CONVERSION;
char* szSendBuf = T2A(strTmpMsg);
//发送给服务端
m_chat->Send(szSendBuf, 200, 0);//200个字节
//显示到列表框
CString strShow = _T("客户端:");
CString strTime;
m_tm = CTime::GetCurrentTime();
strTime = m_tm.Format("%X");
strShow = strTime + strShow;
strShow += strTmpMsg;
m_list.AddString(strShow);
UpdateData(FALSE);
GetDlgItem(IDC_SEND_EDIT)->SetWindowText(_T(""));
}
21,这个时候我们会出现一个BUG 因为在服务器的编辑框添加变量
m_input
然后在重新生成
22,这个时候我们的代码太复杂化了,我们要大大提高代码的可复用性
这个时候我们自己拼接一个函数
在MFCChactClientDlgDlg.cpp里面
//自己拼接的函数
CString CMFCChactClientDlgDlg::CatShowString(CString strInfo,CString strMsg)
{
//时间 + 信息 (昵称)+消息
CString strTime;
CTime tmNow;
tmNow = CTime::GetCurrentTime();
strTime = tmNow.Format("%X");
CString strShow;
strShow = strTime + strShow;
strShow += strInfo;
strShow += strMsg;
return strShow;
}
我们在MFCChactClientDlgDlg.h当中添加拼接函数声明
CString CatShowString(CString s