首页 > 其他 > 详细

使用CAsyncSocket创建网络通信

时间:2021-06-02 22:54:17      阅读:25      评论:0      收藏:0      [点我收藏+]

服务器端界面:

技术分享图片

 

 创建基于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;
    }

 

使用CAsyncSocket创建网络通信

原文:https://www.cnblogs.com/Super-biscuits/p/14843019.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!