服务器端界面:
创建基于CAsyncSocket的通信类
CNewSocket.h
#pragma once #include <afxsock.h> class CNewSocket : public CAsyncSocket // 主Socket { public: CNewSocket(); ~CNewSocket(); virtual void OnReceive(int nErrorCode) override; virtual void OnSend(int nErrorCode) override; UINT m_length; char m_szbuffer[4096]; };
CNewSocket.cpp
1 #include "pch.h" 2 #include "CNewSocket.h" 3 #include"MfcSocketServer.h" 4 #include"MfcSocketServerDlg.h" 5 6 CNewSocket::CNewSocket() 7 { 8 memset(m_szbuffer, 0, sizeof(m_szbuffer)); 9 } 10 CNewSocket::~CNewSocket() 11 { 12 if (m_hSocket != INVALID_SOCKET) 13 { 14 Close(); 15 } 16 } 17 void CNewSocket::OnReceive(int nErrorCode) 18 { 19 m_length = Receive(m_szbuffer, sizeof(m_szbuffer)); // 读取数据到缓冲区 20 m_szbuffer[m_length] = ‘\0‘; 21 CMfcSocketServerApp* pApp = (CMfcSocketServerApp*)AfxGetApp(); 22 23 CMfcSocketServerDlg* pDlg = (CMfcSocketServerDlg*)pApp->m_pMainWnd; 24 pDlg->m_listbox.InsertString(0, m_szbuffer); 25 26 //AsyncSelect(FD_WRITE); // 触发可写入信号,OnSend函数执行 27 CAsyncSocket::OnReceive(nErrorCode); 28 } 29 void CNewSocket::OnSend(int nErrorCode) 30 { 31 CMfcSocketServerApp* pApp = (CMfcSocketServerApp*)AfxGetApp(); 32 33 CMfcSocketServerDlg* pDlg = (CMfcSocketServerDlg*)pApp->m_pMainWnd; 34 35 CString buf; 36 pDlg->m_text.GetWindowTextA(buf); 37 Send(buf.GetString(), sizeof(buf.GetLength())); // 发送消息 38 pDlg->m_text.SetWindowTextA(""); 39 AsyncSelect(FD_READ); // 继续触发可读信号 40 CAsyncSocket::OnSend(nErrorCode); 41 }
创建单独一个监听的套接字
CListentSocket.h
#pragma once #include"pch.h" #include<afxsock.h> #include"CNewSocket.h" class CListenSocket : public CAsyncSocket { public: CListenSocket(); ~CListenSocket(); std::shared_ptr<CNewSocket> m_pSocket; virtual void OnAccept(int nErrorCode) override; virtual void OnSend(int nErrorCode) override; };
在CNewSocket.cpp实现该类的方法
#include"CListentSocket.h" CListenSocket::CListenSocket() { } CListenSocket::~CListenSocket() { } void CListenSocket::OnAccept(int nErrorCode) // Accept事件自动触发 { auto pSocket = std::make_shared<CNewSocket>(); if (Accept(*pSocket)) { pSocket->AsyncSelect(FD_READ); //触发读取消息,此时进入OnReceive函数 m_pSocket = pSocket; } CAsyncSocket::OnAccept(nErrorCode); } void CListenSocket::OnSend(int nErrorCode) { m_pSocket->AsyncSelect(FD_WRITE); // 消息传递 此时进入OnSend函数 CAsyncSocket::OnSend(nErrorCode); }
在主窗口类创建socket对象,并且创建控件变量
// MfcSocketServerDlg.h: 头文件 // #pragma once #include"CListentSocket.h" // CMfcSocketServerDlg 对话框 class CMfcSocketServerDlg : public CDialogEx { // 构造 public: CMfcSocketServerDlg(CWnd* pParent = nullptr); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MFCSOCKETSERVER_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 OnBnClickedButton1(); std::shared_ptr<CListenSocket> m_serversocket; // 智能指针,在该类的构造函数内进行make_sheard CListBox m_listbox; afx_msg void OnBnClickedButton2(); CEdit m_text; };
创建连接服务器的按钮事件处理函数实现
void CMfcSocketServerDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 if (m_serversocket->m_hSocket == INVALID_SOCKET) { BOOL bFlag = m_serversocket->Create(8800, SOCK_STREAM, FD_ACCEPT | FD_WRITE); // 创建套接字 if (!bFlag) { DWORD dw = WSAGetLastError(); AfxMessageBox("创建套接字失败!"); PostQuitMessage(0); return; } (CButton*)GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE); //取消启用按钮 if (!m_serversocket->Listen()) // 监听套接字 { int nErrorCode = m_serversocket->GetLastError(); if (nErrorCode != WSAEWOULDBLOCK) { AfxMessageBox("监听失败!"); m_serversocket->Close(); PostQuitMessage(0); return; } } } }
创建发送按钮的事件处理函数定义
void CMfcSocketServerDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 m_serversocket->OnSend(0); //消息传递,最终传递到CNewSocket的OnSend函数 }
在程序类的InitInstance()函数添加库的初始化
WSADATA wsadata; if (!AfxSocketInit(&wsadata)) { AfxMessageBox(IDP_SOCKETS_INIT_FAILED); return FALSE; }
客户端:
创建套接字类
#pragma once #include <afxsock.h> class ClientSocket : public CAsyncSocket { public: ClientSocket(); ~ClientSocket(); bool m_bConnected; UINT m_nLength; char m_szbuffer[4096]; virtual void OnConnect(int nErrorCode) override; virtual void OnReceive(int nErrorCode) override; virtual void OnSend(int nErrorCode) override; };
cpp实现
#include "pch.h" #include "ClientSocket.h" #include"MfcSocketClient.h" #include"MfcSocketClientDlg.h" ClientSocket::ClientSocket() { memset(m_szbuffer, 0, sizeof(m_szbuffer)); m_bConnected = false; m_nLength = 0; } ClientSocket::~ClientSocket() { if (m_hSocket != INVALID_SOCKET) { Close(); } } void ClientSocket::OnConnect(int nErrorCode) // 由Connect函数触发的事件处理函数,只有在连接成功后执行 { if (nErrorCode == 0) { m_bConnected = true; // 记录连接的状态 // 在主窗口的列表框内显示信息 CMfcSocketClientApp* pApp = (CMfcSocketClientApp*)AfxGetApp(); CMfcSocketClientDlg* pDlg = (CMfcSocketClientDlg*)pApp->m_pMainWnd; CString strTextOut; strTextOut.Format("alread connect to"); strTextOut += pDlg->m_Address; strTextOut += L"\t端口号:"; CString str; str.Format("%d", pDlg->m_Port); strTextOut += str; pDlg->m_MsgR.InsertString(0, strTextOut); // 插入文本 AsyncSelect(FD_READ); //触发读取处理事件->OnReceive } CAsyncSocket::OnConnect(nErrorCode); } void ClientSocket::OnReceive(int nErrorCode) { m_nLength = Receive(m_szbuffer, sizeof(m_szbuffer)); // 读取消息 CMfcSocketClientApp* pApp = (CMfcSocketClientApp*)AfxGetApp(); CMfcSocketClientDlg* pDlg = (CMfcSocketClientDlg*)pApp->m_pMainWnd; CString strTextOut(m_szbuffer); pDlg->m_MsgR.InsertString(0, strTextOut); // 将消息在主窗口显示 memset(m_szbuffer, 0, sizeof(m_szbuffer)); CAsyncSocket::OnReceive(nErrorCode); } void ClientSocket::OnSend(int nErrorCode) { Send(m_szbuffer,m_nLength); m_nLength = 0; memset(m_szbuffer, 0, sizeof(m_szbuffer)); AsyncSelect(FD_READ); // 触发读取处理事件 CAsyncSocket::OnSend(nErrorCode); }
客户端窗口:
在窗口类中创建套接字,控件变量
// MfcSocketClientDlg.h: 头文件 // #pragma once #include"ClientSocket.h" // CMfcSocketClientDlg 对话框 class CMfcSocketClientDlg : public CDialogEx { // 构造 public: CMfcSocketClientDlg(CWnd* pParent = nullptr); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MFCSOCKETCLIENT_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: // IP地址 CString m_Address; // 信息可以在构造函数内初始化具体数值,然后通过update()来更新窗口 // 端口号 int m_Port; // 显示状态和接收到的数据 CListBox m_MsgR; // 要发送的消息 CString m_Msg; //负责通信的异步套接字 ClientSocket m_ClientSocket; // 连接服务器次数 int m_nTryTimes; afx_msg void OnBnClickedButton1(); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnBnClickedButton2(); };
窗口类的方法实现
void CMfcSocketClientDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 if (m_ClientSocket.m_bConnected) { AfxMessageBox("当前已经与服务器建立连接!"); return; } UpdateData(true); if (m_Address.IsEmpty()) { AfxMessageBox("服务器的IP地址不能为空!"); return; } if (m_Port <= 1024) { AfxMessageBox("服务器的端口设置非法!"); return; } GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE); // 取消连接按钮的启用状态 SetTimer(1, 1000, NULL); // 启动定时器进入connect连接 } void CMfcSocketClientDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (m_ClientSocket.m_hSocket == INVALID_SOCKET) { BOOL bFlag = m_ClientSocket.Create(0, SOCK_STREAM, FD_CONNECT); //创建套接字 if (!bFlag) { AfxMessageBox("SOCKET创建失败!"); m_ClientSocket.Close(); PostQuitMessage(0); return; } } m_ClientSocket.Connect(m_Address, m_Port); //连接服务器 if (m_nTryTimes >= 10) //当连接次数大于等于10次的时候结束连接 { KillTimer(1); AfxMessageBox("连接失败!"); GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE); return; } else if (m_ClientSocket.m_bConnected) // 如果连接成功了,结束定时器,启用连接按钮 { KillTimer(1); GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE); return; } //在窗口中提示连接信息 CString strTextOut = "尝试连接服务器第"; m_nTryTimes++; // 累加连接次数 CString str; str.Format("%d", m_nTryTimes); strTextOut += str; strTextOut += L"次。。。"; m_MsgR.AddString(strTextOut); CDialogEx::OnTimer(nIDEvent); } // 发送消息,触发FD_WRITE void CMfcSocketClientDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 UpdateData(TRUE); if (m_ClientSocket.m_bConnected) //如果连接了服务器 { #if UNICODE //将用户输入的数据从CString转化为char *字符串,即Unicode-->ANSI,并保存到m_ClientSocket.m_szBuffer中 int len =WideCharToMultiByte(CP_ACP,0,m_Msg,-1,NULL,0,NULL,NULL); WideCharToMultiByte(CP_ACP,0,m_Msg,-1,m_ClientSocket.m_szbuffer,len,NULL,NULL ); #else strncpy(m_ClientSocket.m_szbuffer, m_Msg, m_Msg.GetLength() + 1); #endif m_ClientSocket.m_nLength = strlen(m_ClientSocket.m_szbuffer); m_ClientSocket.AsyncSelect(FD_WRITE); //触发写事件,发送消息 m_Msg = _T(""); UpdateData(FALSE); } }
依然在程序类的InitInstance()函数中初始化socket库
if (!AfxSocketInit()) { AfxMessageBox(IDP_SOCKETS_INIT_FAILED); return FALSE; }
原文:https://www.cnblogs.com/Super-biscuits/p/14843019.html