实验目标
简单的聊天室程序,采用C/S模型,分为客户端和服务器端程序。是点对点通信的程序。客户端和服务器端通过网络交换聊天的字符串内容,并显示。
实验目的
- 学习如何从CAsyncSocket类派生出自己的WinSock类。
- 理解WinSock类与应用程序框架的关系
- 学习流式套接字对象的使用
- 学习处理网络事件的方法
- 了解MFC编程
实验环境
Windows10 x64,Visual Studio 2017
实验内容
分为两大块,创建客户端和创建服务器端。
客户端
- 使用MFC ApplicationWizard创建客户端应用程序框架
- 为对话框界面添加控件对象
- 为对话框中的控件对象定义相应的成员变量
- 创建从CAsynSocket类继承的派生类
- 为对话框类添加控件对象事件的响应函数
- 为CtalkcDlg对话框类添加其他的成员函数和成员变量
- 添加关于控件变量的初始化代码
- 添加事件函数和成员函数的代码
服务器端
与客户端同理
实验原理
服务器端:
- 创建一个套接字
- 创建Socket,绑定到指定端口
- 启动监听,准备客户端的连接请求
- 接收连接
- 消息的传送
- 关闭套接字
客户端:
- 创建一个套接字
- 创建Socket
- 请求连接服务器
- 消息的传送
- 关闭套接字
实验过程(代码分析)
👉创造程序框架 (MFC基于对话框)
👉添加控件对象
👉添加控件成员变量
CSocket类从CAsynSocket类继承了许多成员函数,封装了Windows套接字应用程序编程接口API。
应用程序类Ctalkc\s App对应文件
VC++自动生成
派生类CMySocket对应文件
对CMySocket进行定义。它是从CAsynSocket类继承下来的派生类,将Socket事件传给对话框,以便执行用户自己的事件处理函数。
class CMySocket:public CAsynSocket
添加事件响应函数,用于连接、断开、和接收
服务器端:
✏️MySocket.h
#pragma once
#include <afxsock.h>
class CtalksDlg;
////////////////////////////////
class CMySocket :
public CAsyncSocket
{
public:
CMySocket();
virtual ~CMySocket();
public:
virtual void OnAccept(int nErrorCode);
virtual void OnClose(int nErrorCode);
virtual void OnReceive(int nErrorCode);
private:
CtalksDlg* m_pDlg;
public:
void SetParent(CtalksDlg* pDlg);
};
✏️MySocket.cpp
#include "talks.h"
#include "pch.h"
#include "MySocket.h"
#include "talksDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
#endif
// CMySocket
CMySocket::CMySocket()
{
m_pDlg = NULL;
}
CMySocket::~CMySocket()
{
m_pDlg = NULL;
}
void CMySocket::SetParent(CtalksDlg* pDlg)
{
m_pDlg = pDlg;
}
#if 0
BEGIN_MESSAGE_MAP(CMySocket, CAsyncSocket)
END_MESSAGE_MAP()
#endif
//CMySocket member functions
void CMySocket::OnAccept(int nErrorCode)
{
if (nErrorCode == 0) m_pDlg->OnAccept();
}
void CMySocket::OnClose(int nErrorCode)
{
if (nErrorCode == 0) m_pDlg->OnClose();
}
void CMySocket::OnReceive(int nErrorCode)
{
if (nErrorCode == 0) m_pDlg->OnReceive();
}
客户端:
✏️MySocket.h
#pragma once
#include <afxsock.h>
class CtalkcDlg;
////////////////////////////////
//CMySocket ÀàµÄ¶¨Òå
class CMySocket :
public CAsyncSocket
{
public:
CMySocket();
virtual ~CMySocket();
public:
virtual void OnConnect(int nErrorCode);
virtual void OnClose(int nErrorCode);
virtual void OnReceive(int nErrorCode);
private:
CtalkcDlg* m_pDlg;
public:
void SetParent(CtalkcDlg* pDlg);
};
✏️MySocket.cpp
#include "talkc.h"
#include "pch.h"
#include "MySocket.h"
#include "talkcDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
#endif
// CMySocket
CMySocket::CMySocket()
{
m_pDlg = NULL;
}
CMySocket::~CMySocket()
{
m_pDlg = NULL;
}
void CMySocket::SetParent(CtalkcDlg* pDlg)
{
// TODO: ÔÚ´Ë´¦Ìí¼ÓʵÏÖ´úÂë.
m_pDlg = pDlg;
}
#if 0
BEGIN_MESSAGE_MAP(CMySocket, CAsyncSocket)
END_MESSAGE_MAP()
#endif
//CMySocket member functions
void CMySocket::OnConnect(int nErrorCode)
{
// TODO: ÔÚ´ËÌí¼ÓרÓôúÂëºÍ/»òµ÷ÓûùÀà
if (nErrorCode == 0) m_pDlg -> OnConnect();
}
void CMySocket::OnClose(int nErrorCode)
{
// TODO: ÔÚ´ËÌí¼ÓרÓôúÂëºÍ/»òµ÷ÓûùÀà
if (nErrorCode == 0) m_pDlg->OnClose();
}
void CMySocket::OnReceive(int nErrorCode)
{
// TODO: ÔÚ´ËÌí¼ÓרÓôúÂëºÍ/»òµ÷ÓûùÀà
if (nErrorCode == 0) m_pDlg->OnReceive();
}
对话框类CTalkDlg对应文件
主要是对控件变量的声明和定义。
服务器端:
✏️talksDlg.h
// talksDlg.h: 头文件
//
#pragma once
#include "MySocket.h"
// CtalksDlg 对话框
class CtalksDlg : public CDialogEx
{
// 构造
public:
CtalksDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_TALKS_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLbnSelchangeList2();
CButton m_btnListen;
CString m_strServName;
int m_nServPort;
CString m_strMsg;
CListBox m_listSent;
CListBox m_listReceived;
afx_msg void OnButtonClose();
afx_msg void OnButtonListen();
afx_msg void OnSendMsg();
CMySocket m_sListenSocket;
CMySocket m_sConnectSocket;
void OnClose();
void OnAccept();
void OnReceive();
};
✏️talksDlg.cpp
// talksDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "talks.h"
#include "talksDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CtalksDlg 对话框
CtalksDlg::CtalksDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_TALKS_DIALOG, pParent)
, m_strServName(_T(""))
, m_nServPort(0)
, m_strMsg(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CtalksDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BUTTON_LISTEN, m_btnListen);
DDX_Text(pDX, IDC_EDIT_SERVNAME, m_strServName);
DDX_Text(pDX, IDC_EDIT_SERVPORT, m_nServPort);
DDX_Text(pDX, IDC_EDIT_MSG, m_strMsg);
DDX_Control(pDX, IDC_LIST_SENT, m_listSent);
DDX_Control(pDX, IDC_LIST_RECEIVED, m_listReceived);
}
BEGIN_MESSAGE_MAP(CtalksDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CtalksDlg::OnButtonClose)
ON_BN_CLICKED(IDC_BUTTON_LISTEN, &CtalksDlg::OnButtonListen)
ON_BN_CLICKED(IDOK, &CtalksDlg::OnSendMsg)
END_MESSAGE_MAP()
// CtalksDlg 消息处理程序
BOOL CtalksDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
m_strServName = "localhost";
m_nServPort = 1000;
UpdateData(FALSE);
m_sListenSocket.SetParent(this);
m_sConnectSocket.SetParent(this);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CtalksDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CtalksDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CtalksDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CtalksDlg::OnButtonClose()
{
// TODO: 在此添加控件通知处理程序代码
OnClose();
}
void CtalksDlg::OnButtonListen()
{
UpdateData(TRUE);
GetDlgItem(IDC_BUTTON_LISTEN)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERVNAME)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERVPORT)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_SERVNAME)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_SERVPORT)->EnableWindow(FALSE);
m_sListenSocket.Create(m_nServPort);
m_sListenSocket.Listen();
}
void CtalksDlg::OnSendMsg()
{
// TODO: 在此添加控件通知处理程序代码
int nLen;
int nSent;
UpdateData(TRUE);
if (!m_strMsg.IsEmpty())
{
nLen = m_strMsg.GetLength();
nSent = m_sConnectSocket.Send(LPCTSTR(m_strMsg), nLen);
if (nSent != SOCKET_ERROR)
{
m_listSent.AddString(m_strMsg);
UpdateData(FALSE);
}
else {
AfxMessageBox(_T("信息发送错误!", MB_OK | MB_ICONSTOP));
}
m_strMsg.Empty();
UpdateData(FALSE);
}
}
void CtalksDlg::OnClose()
{
m_listReceived.AddString("服务器已经收到啦OnClose的消息♥");
m_sConnectSocket.Close();
GetDlgItem(IDC_EDIT_MSG)->EnableWindow(FALSE);
GetDlgItem(IDOK)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_MSG)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(FALSE);
while (m_listSent.GetCount() != 0) m_listSent.DeleteString(0);
while (m_listReceived.GetCount() != 0) m_listReceived.DeleteString(0);
GetDlgItem(IDC_BUTTON_LISTEN)->EnableWindow(TRUE);
GetDlgItem(IDC_EDIT_SERVNAME)->EnableWindow(TRUE);
GetDlgItem(IDC_EDIT_SERVPORT)->EnableWindow(TRUE);
GetDlgItem(IDC_STATIC_SERVNAME)->EnableWindow(TRUE);
GetDlgItem(IDC_STATIC_SERVPORT)->EnableWindow(TRUE);
}
void CtalksDlg::OnAccept()
{
// TODO: 在此处添加实现代码.
m_listReceived.AddString("服务器已经收到啦OnAccept的消息!!");
m_sListenSocket.Accept(m_sConnectSocket);
GetDlgItem(IDC_EDIT_MSG)->EnableWindow(TRUE);
GetDlgItem(IDOK)->EnableWindow(TRUE);
GetDlgItem(IDC_STATIC_MSG)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(TRUE);
}
void CtalksDlg::OnReceive()
{
char *pBuf = new char[1025];
int nBufSize = 1024;
int nReceived;
CString strReceived;
m_listReceived.AddString("服务器已经收到啦OnReceive的消息!!");
nReceived = m_sConnectSocket.Receive(pBuf, nBufSize);
if (nReceived != SOCKET_ERROR)
{
pBuf[nReceived] = NULL;
strReceived = pBuf;
m_listReceived.AddString(strReceived);
UpdateData(FALSE);
}
else {
AfxMessageBox(_T("信息接收出错啦!!", MB_OK | MB_ICONSTOP));
}
}
客户端:
✏️talkcDlg.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >1000
// talkcDlg.h: 头文件
//
#include "MySocket.h"
#pragma once
// CtalkcDlg 对话框
class CtalkcDlg : public CDialogEx
{
// 构造
public:
void OnClose();
void OnConnect();
void OnReceive();
CMySocket m_sConnectSocket;
CtalkcDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_TALKC_DIALOG };
#endif
CListBox m_listSent;
CListBox m_listReceived;
CButton m_btnConnect;
CString m_strMsg;
CString m_strServName;
int m_nServPort;
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnButtonClose();
afx_msg void OnButtonConnect();
afx_msg void OnSendMsg();
};
✏️talkcDlg.cpp
// talkcDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "talkc.h"
#include "talkcDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CtalkcDlg 对话框
CtalkcDlg::CtalkcDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_TALKC_DIALOG, pParent)
, m_strServName(_T(""))
, m_nServPort(0)
, m_strMsg(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CtalkcDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BUTTON_CONNECT, m_btnConnect);
DDX_Text(pDX, IDC_EDIT_SERNAME, m_strServName);
DDX_Text(pDX, IDC_EDIT_SERVPORT, m_nServPort);
DDX_Text(pDX, IDC_EDIT_MSG, m_strMsg);
DDX_Control(pDX, IDC_LIST_SENT, m_listSent);
DDX_Control(pDX, IDC_LIST_RECEIVED, m_listReceived);
}
BEGIN_MESSAGE_MAP(CtalkcDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CtalkcDlg::OnButtonClose)
ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CtalkcDlg::OnButtonConnect)
ON_BN_CLICKED(IDOK, &CtalkcDlg::OnSendMsg)
END_MESSAGE_MAP()
// CtalkcDlg 消息处理程序
BOOL CtalkcDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
m_strServName = "localhost";
m_nServPort = 1000;
UpdateData(FALSE);
GetDlgItem(IDC_BUTTON_CONNECT)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERNAME)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERVPORT)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_SERVNAME)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_SERVPORT)->EnableWindow(FALSE);
m_sConnectSocket.SetParent(this);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CtalkcDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CtalkcDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CtalkcDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CtalkcDlg::OnButtonConnect()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
GetDlgItem(IDC_BUTTON_CONNECT)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERNAME)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERVPORT)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_SERVNAME)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_SERVPORT)->EnableWindow(FALSE);
m_sConnectSocket.Create();
m_sConnectSocket.Connect(m_strServName, m_nServPort);
}
void CtalkcDlg::OnSendMsg()
{
// TODO: 在此添加控件通知处理程序代码
int nLen;
int nSent;
UpdateData(TRUE);
if (!m_strMsg.IsEmpty())
{
nLen = m_strMsg.GetLength();
nSent = m_sConnectSocket.Send(LPCTSTR(m_strMsg), nLen);
if (nSent != SOCKET_ERROR)
{
m_listSent.AddString(m_strMsg);
UpdateData(FALSE);
}
else {
AfxMessageBox(_T("信息发送错误!", MB_OK | MB_ICONSTOP));
}
m_strMsg.Empty();
UpdateData(FALSE);
}
}
void CtalkcDlg::OnButtonClose()
{
// TODO: 在此添加控件通知处理程序代码
OnClose();
}
void CtalkcDlg::OnReceive()
{
// TODO: 在此处添加实现代码.
char *pBuf = new char[1025];
int nBufSize = 1024;
int nReceived;
CString strReceived;
nReceived = m_sConnectSocket.Receive(pBuf, nBufSize);
if (nReceived != SOCKET_ERROR)
{
pBuf[nReceived] = NULL;
strReceived = pBuf;
m_listReceived.AddString(strReceived);
UpdateData(FALSE);
}
else {
AfxMessageBox(_T("信息接收出错啦!!", MB_OK | MB_ICONSTOP));
}
}
void CtalkcDlg::OnConnect()
{
// TODO: 在此处添加实现代码.
//开放连接配置的相关控件,如“连接”按钮、服务器名称、端口的文本框和标签
GetDlgItem(IDC_EDIT_MSG)->EnableWindow(TRUE);
GetDlgItem(IDOK)->EnableWindow(TRUE);
GetDlgItem(IDC_STATIC_MSG)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(TRUE);
}
void CtalkcDlg::OnClose()
{
// TODO: 在此处添加实现代码.
m_sConnectSocket.Close();
GetDlgItem(IDC_EDIT_MSG)->EnableWindow(FALSE);
GetDlgItem(IDOK)->EnableWindow(FALSE);
GetDlgItem(IDC_STATIC_MSG)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(FALSE);
while (m_listSent.GetCount() != 0) m_listSent.DeleteString(0);
while (m_listReceived.GetCount() != 0) m_listReceived.DeleteString(0);
GetDlgItem(IDC_BUTTON_CONNECT)->EnableWindow(TRUE);
GetDlgItem(IDC_EDIT_SERVNAME)->EnableWindow(TRUE);
GetDlgItem(IDC_EDIT_SERVPORT)->EnableWindow(TRUE);
GetDlgItem(IDC_STATIC_SERVNAME)->EnableWindow(TRUE);
GetDlgItem(IDC_STATIC_SERVPORT)->EnableWindow(TRUE);
}
实验界面结果展示
实验过程中遇到的问题
⛔️关于字符的问题
💚在配置中调属性,或宏定义_T_。解决该报错
实验参考书
客户端
服务器端