• MFC中Socket网络通讯


    • UDP通信:User Datagram Protocol 用户数据报协议。是一种无连接的简单的不可靠信息传送服务。OSI七层协议:www.cnblogs.com/wxgblogs/p/5641643.html

    新建基于Dialog的MFC程序,在CxxxApp类的 InitInstance()中添加  AfxSocketInit();(初始化Socket)

    新建一个类CSockU 基类为MFC中的CSocket,右键类名添加虚函数 OnReceive()

    //////////// 头文件 SockU.h ////////////////
    #include <afxsock.h>
    /////////////////////////////////////////////////////////////////////////////
    // CSockU command target
    
    class CSockU : public CSocket
    {
    // Attributes
    public:
    
    // Operations
    public:
        CSockU();
        virtual ~CSockU();
    
    // Overrides
    public:
        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CSockU)
        public:
        virtual void OnReceive(int nErrorCode);
        //}}AFX_VIRTUAL
    
        // Generated message map functions
        //{{AFX_MSG(CSockU)
            // NOTE - the ClassWizard will add and remove member functions here.
        //}}AFX_MSG
    
    // Implementation
    protected:
    };
    ///////////////  SockU.cpp文件 ////////////////
    CSockU::CSockU()
    {
    }
    
    CSockU::~CSockU()
    {
    }
    
    
    // Do not edit the following lines, which are needed by ClassWizard.
    #if 0
    BEGIN_MESSAGE_MAP(CSockU, CSocket)
        //{{AFX_MSG_MAP(CSockU)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    #endif    // 0
    
    /////////////////////////////////////////////////////////////////////////////
    // CSockU member functions
    #include "15_1UDPDlg.h"
    void CSockU::OnReceive(int nErrorCode) 
    {//socket接收消息
        CString szIP; //存放消息来源的IP地址
        UINT nPort;   //存放消息来源的端口号
        char buf[512] = {0}; //存消息
        this->ReceiveFrom(buf, sizeof(buf), szIP, nPort);//UDP接收消息
        CMy15_1UDPDlg* pDlg = (CMy15_1UDPDlg*)::AfxGetMainWnd();
        pDlg->OnReceive(buf,szIP);
            
        CSocket::OnReceive(nErrorCode);
    }

    在主对话框类添加:

    void OnReceive(LPCSTR szText, LPCSTR szIP);
    CSockU m_sock;

    在OnInitDialog()中

    BOOL CMy15_1UDPDlg::OnInitDialog()
    {
        CDialog::OnInitDialog();
    
        // Set the icon for this dialog.  The framework does this automatically
        //  when the application's main window is not a dialog
        SetIcon(m_hIcon, TRUE);            // Set big icon
        SetIcon(m_hIcon, FALSE);        // Set small icon
        
        // TODO: Add extra initialization here
        //创建socket  UDP:SOCK_DGRAM  TCP:SOCK_STREAM
        BOOL b = m_sock.Create(8811, SOCK_DGRAM);
        SetDlgItemText(IDC_IP,"192.168.1.110");
        SetDlgItemText(IDC_PORT, "8811");
        DWORD nErr = GetLastError();
        if(WSANOTINITIALISED == nErr)
        {//10093 error 表示socket未初始化
            AfxMessageBox("A successful AfxSocketInit must occur before using this API.");
        }
        else if(WSAEADDRINUSE == nErr)
        {// 10048 error 表示端口被占用
            AfxMessageBox("The specified address is already in use.");
        }
        
        return TRUE;  // return TRUE  unless you set the focus to a control
    }
    {//发送按钮的消息响应函数
        CString str;
        GetDlgItemText(IDC_INPUT, str);
        if(str.IsEmpty())
        {
            AfxMessageBox("不能发送空文字。");
            return;
        }
        CString szIP;
        GetDlgItemText(IDC_IP,szIP);
        //UDP发送消息给IP地址为szIP,端口号8811(接收时要一致)
        m_sock.SendTo(str,str.GetLength(),8811,szIP);
    }
    void CMyUDPDlg::OnReceive(LPCSTR szText, LPCSTR szIP)
    {
        CString str = szIP;
        str += ":
    ";//换行
        str += szText;
        str += "
    ";
        CEdit* pwnd = (CEdit*)GetDlgItem(IDC_HIST);
        int len = pwnd->GetWindowTextLength();
        pwnd->SetSel(len,-1);
        pwnd->ReplaceSel(str);
    }
    •  TCP通信:TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

    1. Client 的程序

    新建基于Dialog的MFC程序,在CxxxApp类的 InitInstance()中添加  AfxSocketInit();(初始化Socket)

    新建一个基类为CSocket的类 CSockC

    // SockC.h : header file
    
    class CSockC : public CSocket
    {
    // Attributes
    public:
    
    // Operations
    public:
        CSockC();
        virtual ~CSockC();
    
    // Overrides
    public:
        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CSockC)
        public:
        virtual void OnReceive(int nErrorCode);
        //}}AFX_VIRTUAL
    
        // Generated message map functions
        //{{AFX_MSG(CSockC)
            // NOTE - the ClassWizard will add and remove member functions here.
        //}}AFX_MSG
    
    // Implementation
    protected:
    };
    
    ///////////////// CSockC.cpp文件  ///////////////////
    
    CSockC::CSockC()
    {
    }
    
    CSockC::~CSockC()
    {
    }
    
    
    // Do not edit the following lines, which are needed by ClassWizard.
    #if 0
    BEGIN_MESSAGE_MAP(CSockC, CSocket)
        //{{AFX_MSG_MAP(CSockC)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    #endif    // 0
    
    /////////////////////////////////////////////////////////////////////////////
    // CSockC member functions
    
    void CSockC::OnReceive(int nErrorCode) 
    {
        char s[2048] = {0};
        CString szIP;
        UINT nPort;
        //TCP接收消息函数
        Receive(s,sizeof(s));
        //获取消息来源的IP地址和端口号
        GetPeerName(szIP, nPort);
        TCP_ClientDlg* pDlg = (TCP_ClientDlg*)AfxGetMainWnd();
        pDlg->OnReceive(s);
        
        CSocket::OnReceive(nErrorCode);
    }

    在主对话框中添加成员函数和成员变量:

    void OnReceive(CString szText);
    CSockC m_sock;

    在 OnInitDialog() 中:

    BOOL TCP_ClientDlg::OnInitDialog()
    {
        CDialog::OnInitDialog();
    
        // Set the icon for this dialog.  The framework does this automatically
        //  when the application's main window is not a dialog
        SetIcon(m_hIcon, TRUE);            // Set big icon
        SetIcon(m_hIcon, FALSE);        // Set small icon
        
        // TODO: Add extra initialization here
        if(!m_sock.Create())//创建TCP的socket
        {
            AfxMessageBox("网络创建失败!");
        }
        if(!m_sock.Connect("192.168.1.118", 8881))
        {
            int nErr = GetLastError();//10061连接不到服务器
            AfxMessageBox("连接网络失败,请检查网络是否连接!");
        }
        return TRUE;  // return TRUE  unless you set the focus to a control
    }

    其他

    void TCP_ClientDlg::OnOK() 
    {//发送按钮的消息响应函数
        CString str;
        GetDlgItemText(IDC_INPUT, str);
        if(str.IsEmpty())
        {
            MessageBox("不能发送空文字!");
        }
        //TCP的发送消息函数
        m_sock.Send(str, str.GetLength());
    //    CDialog::OnOK();
    }
    
    void TCP_ClientDlg::OnReceive(CString szText)
    {
        int nLen = m_hist.GetWindowTextLength();
        m_hist.SetSel(nLen,-1);
        m_hist.ReplaceSel(szText);
    }
    •  Server 的编程

    首先,在CxxxApp中的InitInstance()中初始化Socket  添加  AfxSocketInit();。在CxxxApp中添加一个成员变量 存放socket类指针的链表, List<CClientSocket*,CClientSocket*> m_list;

    建立 侦听(接待)Socket类 —— CListenSocket ,和 具体的Socket类(用来接收客户端的消息)——CClientSocket

    1. CListenSocket类

    // ListenSocket.h : header file
    
    class CListenSocket : public CSocket
    {
    // Attributes
    public:
    
    // Operations
    public:
        CListenSocket();
        virtual ~CListenSocket();
    
    // Overrides
    public:
        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CListenSocket)
        public:
        virtual void OnAccept(int nErrorCode);
        //}}AFX_VIRTUAL
    
        // Generated message map functions
        //{{AFX_MSG(CListenSocket)
            // NOTE - the ClassWizard will add and remove member functions here.
        //}}AFX_MSG
    
    // Implementation
    protected:
    };
    
    //////////////// 实现文件 ListenSocket.cpp ////////////////
    CListenSocket::CListenSocket()
    {
    }
    
    CListenSocket::~CListenSocket()
    {
    }
    
    
    // Do not edit the following lines, which are needed by ClassWizard.
    #if 0
    BEGIN_MESSAGE_MAP(CListenSocket, CSocket)
        //{{AFX_MSG_MAP(CListenSocket)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    #endif    // 0
    
    /////////////////////////////////////////////////////////////////////////////
    // CListenSocket member functions
    
    void CListenSocket::OnAccept(int nErrorCode) 
    {//等待客户连接
        CClientSocket* p = new CClientSocket;
        if(!Accept(*p))//是否能接收成功
        {
            delete p;
            return;
        }
        CString szIP;
        UINT nPort;
        p->GetPeerName(szIP,nPort);//获取IP和端口
        ServerDlg* pDlg = (ServerDlg*)::AfxGetMainWnd();
        pDlg->OnAccept(szIP,nPort);
        theApp.m_list.AddTail(p);//把指针添加到链表m_list的尾部
    
        CSocket::OnAccept(nErrorCode);
    }

    2. CClientSocket类

    //////////// 头文件 ///////////
    class CClientSocket : public CSocket
    {
    // Attributes
    public:
    
    // Operations
    public:
        CClientSocket();
        virtual ~CClientSocket();
    
    // Overrides
    public:
        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CClientSocket)
        public:
        virtual void OnReceive(int nErrorCode);
        virtual void OnClose(int nErrorCode);
        //}}AFX_VIRTUAL
    
        // Generated message map functions
        //{{AFX_MSG(CClientSocket)
            // NOTE - the ClassWizard will add and remove member functions here.
        //}}AFX_MSG
    
    // Implementation
    protected:
    };
    
    ////////////////// 实现文件 //////////////
    CClientSocket::CClientSocket()
    {
    }
    
    CClientSocket::~CClientSocket()
    {
    }
    
    
    // Do not edit the following lines, which are needed by ClassWizard.
    #if 0
    BEGIN_MESSAGE_MAP(CClientSocket, CSocket)
        //{{AFX_MSG_MAP(CClientSocket)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    #endif    // 0
    
    /////////////////////////////////////////////////////////////////////////////
    // CClientSocket member functions
    
    void CClientSocket::OnReceive(int nErrorCode) 
    {//有客户发送
        char s[2048] = {0};
        CString szIP;
        UINT nPort;
        int nLen = this->Receive(s, sizeof(s));//接收消息
        this->GetPeerName(szIP,nPort);//获取IP和端口
        ServerDlg* p = (ServerDlg*)::AfxGetMainWnd();
        p->OnReceive(s,szIP,nPort);
        //给所有的客户转发消息
        POSITION pos = theApp.m_list.GetHeadPosition();
        CString str;
        COleDateTime time = COleDateTime::GetCurrentTime();
        str.Format("%s-%d:(%s)
    %s
    ",szIP,nPort,time.Format("%H:%M:%S"),s);
        while(pos)
        {
            CClientSocket* pSock = theApp.m_list.GetNext(pos);
            pSock->Send(str,str.GetLength());
        }
        
        CSocket::OnReceive(nErrorCode);
    }
    
    void CClientSocket::OnClose(int nErrorCode) 
    {
        // TODO: Add your specialized code here and/or call the base class
        POSITION pos = theApp.m_list.GetHeadPosition();
        while(pos)
        {
            if(theApp.m_list.GetAt(pos) == this)
            {
                theApp.m_list.RemoveAt(pos);
                break;
            }
            theApp.m_list.GetNext(pos);
        }
        delete this;
    
        CSocket::OnClose(nErrorCode);
    }

     主对话框类添加:

    void OnAccept(CString szIP,UINT nPort);
    void OnReceive(CString szText,CString szIP,UINT nPort);
    CListenSocket m_socket;

    主对话框的实现文件

    BOOL ServerDlg::OnInitDialog()
    {
        CDialog::OnInitDialog();
    
        // Set the icon for this dialog.  The framework does this automatically
        //  when the application's main window is not a dialog
        SetIcon(m_hIcon, TRUE);            // Set big icon
        SetIcon(m_hIcon, FALSE);        // Set small icon
        
        // TODO: Add extra initialization here
        if(!m_socket.Create(8881))//端口为8881
        {
            int nErr = GetLastError();//nErr=10048端口冲突
            ::AfxMessageBox("网络创建失败!");
        }
        m_socket.Listen();//开始侦听
        
        return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    // If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.
    
    void ServerDlg::OnPaint() 
    {
        if (IsIconic())
        {
            CPaintDC dc(this); // device context for painting
    
            SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
    
            // Center icon in client rectangle
            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;
    
            // Draw the icon
            dc.DrawIcon(x, y, m_hIcon);
        }
        else
        {
            CDialog::OnPaint();
        }
    }
    
    // The system calls this to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR ServerDlg::OnQueryDragIcon()
    {
        return (HCURSOR) m_hIcon;
    }
    
    void ServerDlg::OnOK() 
    {
        // TODO: Add extra validation here
        
    //    CDialog::OnOK();
    }
    
    void ServerDlg::OnReceive(CString szText, CString szIP, UINT nPort)
    {
        CString str;
        str.Format("%s-%d:
    %s
    ",szIP,nPort,szText);
        int nLen = m_txt.GetWindowTextLength();
        m_txt.SetSel(nLen,-1);
        m_txt.ReplaceSel(str);
    //    MessageBox("有消息");
    }
    
    void ServerDlg::OnAccept(CString szIP, UINT nPort)
    {
        CString str;
        str.Format("%s-%d已连接
    ",szIP,nPort);
        int nLen = m_txt.GetWindowTextLength();
        m_txt.SetSel(nLen,-1);
        m_txt.ReplaceSel(str);    
    //    MessageBox("有客户"+ str + "连接");
    
    }

     可以看看:www.cnblogs.com/happykoukou/p/8038701.html

    常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。

    昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
  • 相关阅读:
    第二次冲刺第六天
    第二次冲刺第五天
    第二次冲刺第四天
    Java多线程学习篇(三)Lock
    Java多线程学习篇(二)synchronized
    Java多线程学习篇(一)
    codeforces 895D
    模运算的乘法逆元
    codeforces 889B
    codeforces 878C
  • 原文地址:https://www.cnblogs.com/htj10/p/10817932.html
Copyright © 2020-2023  润新知