⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.cpp

📁 网络编程最基本最常用的网络端和客户端的程序实现
💻 CPP
字号:
#include <afxwin.h>
#include <afxcmn.h>
#include <afxdlgs.h>
#include <afxsock.h>
#include "setup.h"
#include "resource.h"
//
/****************************************************************************
*   显示错误信息
*   输入参数
*         hDlg : 窗口的Handle
*   nErrorCode : 调用AsyncSocket成员函数时, 发生错误的错误值
*****************************************************************************/
void ShowErrorMessage(HWND hDlg, int nErrorCode)
{
    LPVOID lpMsgBuf;
//
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
                  FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  nErrorCode,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR)&lpMsgBuf,
                  0, NULL);
    ::MessageBox(hDlg, (LPCTSTR)lpMsgBuf, "错误", MB_OK | MB_ICONSTOP);
    LocalFree(lpMsgBuf);
};
//
/*****************************************************************************
*    主程序对话框的类
*****************************************************************************/
class CClientDlg : public CDialog
{
public:
    CClientDlg(CWnd *pParent = NULL);
//
    virtual BOOL OnInitDialog();
    afx_msg void OnSendbtn();
    afx_msg void OnSetupConnect();
    afx_msg void OnDisconnect();
    afx_msg void OnDestroy();
    afx_msg void OnChange();
//
    void OnReceive(int nErrorCode);   // 接收传来信息时的处理函数
//
    struct _tagAsyncSocket : public CAsyncSocket
    // 建立一个结构使这个结构能继承CAsyncSocket类,
    // 此结构主要是用来 Overlap Receive() 这个CAsyncSocket 的函数成员
    {   
        _tagAsyncSocket(CClientDlg *pSocket) { m_pSocket = pSocket; };
        // 结构的建构者, 接受一个CClientDlg 类指针的参数
        virtual void OnReceive(int nErrorCode)
        {
            if (nErrorCode == 0)
                // 如果没有发生错误, 则调用CClientDlg的函数成员OnReceive().
                m_pSocket->OnReceive(nErrorCode);
            else
                ShowErrorMessage(::GetDesktopWindow(), GetLastError());
        };
        CClientDlg *m_pSocket;
    };
//
protected:
    CString m_lpszName;         // 用户名称
    CRichEditCtrl *m_pListmsg;  // 显示传来的信息
    CRichEditCtrl *m_pSendmsg;  // 传送的信息
    HICON m_hIcon;              // Icon 的Handle   
    struct _tagAsyncSocket *m_pSocket;
    // CAsyncSocket的对象, 用来接收连线的状态及信息
//
    void SetupIcon(BOOL bIcon = FALSE);  // 更改Icon的处理程序
//
    DECLARE_MESSAGE_MAP()   
};
//
CClientDlg::CClientDlg(CWnd *pParent)
           : CDialog(IDD_CLIENTDLG, pParent)
{
    m_lpszName = CString(_T(""));
    m_pListmsg = NULL;
    m_pSendmsg = NULL;
    m_pSocket = NULL;
    m_hIcon = NULL;
};
//
BEGIN_MESSAGE_MAP(CClientDlg, CDialog)
    ON_BN_CLICKED(IDC_SENDBTN, OnSendbtn)
    ON_COMMAND(IDC_DISCONNECT, OnDisconnect)
    ON_COMMAND(IDM_SETUPCONNECT, OnSetupConnect)
    ON_WM_DESTROY()
    ON_EN_CHANGE(IDC_SENDMSG, OnChange)
END_MESSAGE_MAP()
//
BOOL CClientDlg::OnInitDialog()
{
    DWORD dwStyle = ::GetClassLong(GetSafeHwnd(), GCL_STYLE);
    dwStyle |= CS_NOCLOSE;
    ::SetClassLong(GetSafeHwnd(), GCL_STYLE, dwStyle);
//
    SetupIcon();
    m_pListmsg = (CRichEditCtrl*)GetDlgItem(IDC_LISTMSG);
    // 取得CRichEditCtrl 的控件
    m_pSendmsg = (CRichEditCtrl*)GetDlgItem(IDC_SENDMSG);
//
    m_pSendmsg->SetEventMask(m_pSendmsg->GetEventMask() | ENM_CHANGE);
    // 设置处理CHANGE的事件
//
    return TRUE;
};
//
void CClientDlg::OnDestroy()
{
    if (m_pSocket)  // 如果已经连线
    {
        m_pSocket->Close();  // 关闭连线并释放资源
        delete m_pSocket;
        m_pSocket = NULL;
    };
};
//
/********************************************************************************
*  终止目前的连线
*  输入参数 : 无
*********************************************************************************/
void CClientDlg::OnDisconnect()
{
    if (m_pSocket)
    {
        m_pSocket->ShutDown(); 
        // 停止连线并释放资源, Socket 并未关闭
        delete m_pSocket;
        m_pSocket = NULL;
    };
    SetupIcon();
    CMenu *menu = GetMenu();  // 更改选项(MENU) 的状态
    if (menu)
    {
        menu->EnableMenuItem(IDM_SETUPCONNECT, MF_BYCOMMAND | MF_ENABLED);
    };
    CString str = _T("Client - [未连线...]");
    SetWindowText(str);
    m_pSendmsg->SetOptions(ECOOP_SET, ECO_READONLY);
    // 因为未连线,所以将的CRichEditCtrl控件设成惟读
};
//
/*******************************************************************************
*                          设置连线(主机及连接端口)
*      输入参数 : 无
********************************************************************************/
void CClientDlg::OnSetupConnect()
{
    CSetupDlg dlg;
//
    if (dlg.DoModal() == IDOK)  // 如果已设置完成
    {
        m_pSocket = new _tagAsyncSocket(this);
        // 配置 ASyncSocket 的资源
        if (!m_pSocket->Create())
        // 在客户端使用时可直接使用内定值
        // 如果无法开启WinSock
        {
            delete m_pSocket;  // 释放之前所配置的资源
            m_pSocket = NULL;
            ShowErrorMessage(GetSafeHwnd(), GetLastError());
            return;
        };
        SetupIcon(TRUE);    //更换图标, 代表已经连线
        m_pSocket->Connect(dlg.m_lpszIPaddr, dlg.m_nPort);
        // 连线至主机, 如果成功,此时对AsyncSocket类来说会触发 OnConnect()事件,
        // 如果我们要处理的话, 那必须调用Overlap OnConnect()事件,
        // 此事件如同其他AsyncSocket的成员函数都属于AsyncSocket的 Callback 函数
        m_lpszName = dlg.m_lpszName;
        CString str = _T("Client - ");
        str += dlg.m_lpszName + _T(" [交谈中...]");
        SetWindowText(str);
        CMenu *menu = GetMenu();
        if (menu)
        {
            menu->EnableMenuItem(IDM_SETUPCONNECT, MF_BYCOMMAND | MF_GRAYED);
        };
        m_pSendmsg->SetOptions(ECOOP_XOR, ECO_READONLY);
        // 已经连线,所以取消CRichEditCtrl控件的只读设置
    };
};
//
/********************************************************************************
*                         按下传送信息的按钮
*     输入参数 : 无 
*********************************************************************************/
void CClientDlg::OnSendbtn()
{
    int len;    // 所要传送信息的长度
    int sent;   // 真正传送的长度
    CString s, s1 = m_lpszName;
//
    m_pSendmsg->GetWindowText(s);
    s1 += _T(" Say :\n") + s;
    len = s1.GetLength();
    sent = m_pSocket->Send((LPCTSTR)s1, len);
    // 调用 CAsyncSocket 的成员函数 Sned()来传送信息
    // 如果成功传送, 则传回传送的字符数,
    // 否则传回 SOCKET_ERROR ,此时可用 GetLastError() 取得信息的错误值 
    if (sent == SOCKET_ERROR)
    {
        ShowErrorMessage(GetSafeHwnd(), GetLastError());
        return;
    }
    else
    {
        m_pListmsg->GetWindowText(s1);
        if (s1.IsEmpty())
            s1 = CString(_T("----->")) + s;
        else
            s1 += CString(_T("\n----->")) + s;
        m_pListmsg->SetWindowText(s1);    // 将传送的信息显示在窗口中
        m_pSendmsg->SetWindowText(_T(""));
    };
};
//
/*************************************************************************************
*           接收信息的处理程序 : 此函数被 Overlap 函数 OnReceive() 所调用
*     输入参数 :
*          nErrorCode : 0 为正确 
*                       非 "零" 值错误
*     注意 : 此参数在此函数中不需处理
**************************************************************************************/
void CClientDlg::OnReceive(int nErrorCode)
{
    _TCHAR *buf;
    int size = 1024;
    int nRtn;
    CString str;
//
    buf = new _TCHAR[1024];
    ::memset(buf, 0, sizeof(_TCHAR)*1024);
    nRtn = m_pSocket->Receive(buf, size);
    // 设置接受信息的最大长度
    // 如果成功则传回接收的数据长度, 否则传回 SOCKET_ERROR
    if (nRtn == SOCKET_ERROR)
    {
        ShowErrorMessage(GetSafeHwnd(), GetLastError());
    }
    else
    {
        m_pListmsg->GetWindowText(str);
        str += CString(_T("\n")) + CString(buf);
        m_pListmsg->SetWindowText(str);
        // 将接收的信息加至窗口中
    };
};
//
/**********************************************************************************
*                   设置连线时的图标
*      输入参数 :
*           bIcon : TRUE 为连线中的图标
*                 : FALSE 未连线, 此值为内定值
***********************************************************************************/
void CClientDlg::SetupIcon(BOOL bIcon)
{
    LPCTSTR id = (bIcon) ? MAKEINTRESOURCE(IDI_NET08)
                         : MAKEINTRESOURCE(IDI_TRFFC10C);
    m_hIcon = ::LoadIcon(AfxGetInstanceHandle(), id);
    SetIcon(m_hIcon, FALSE);
    SetIcon(m_hIcon, TRUE);
};
//
/*********************************************************************************
*                    输入的信息窗口内容被改变时
*       输入参数 : 无
**********************************************************************************/
void CClientDlg::OnChange()
{
    CString str;
//
    m_pSendmsg->GetWindowText(str);
    str.IsEmpty()? GetDlgItem(IDC_SENDBTN)->EnableWindow(FALSE)
                  : GetDlgItem(IDC_SENDBTN)->EnableWindow();
};
//
/**********************************************************************************
*                       主程序的类
***********************************************************************************/
class CClientApp : public CWinApp
{
public:
    CClientApp() {};
//
    BOOL InitInstance()
    {
        AfxInitRichEdit();
        // 因为在程序中使用了 CRichEditCtrl 这个控件所以要先调用这个API
        // 注意:这个API要放在 InitInstance这虚拟函数中          
        AfxSocketInit();
        // 使用 Winsock API
//
        CDialog *dlg = new CClientDlg;
        m_pMainWnd = dlg;
        dlg->DoModal();
//
        return TRUE;
    };
} theApp;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -