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 += ":\r\n";//换行
    str += szText;
    str += "\r\n";
    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)\r\n%s\r\n",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:\r\n%s\r\n",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已连接\r\n",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

posted @ 2019-05-06 09:49  htj10  阅读(1695)  评论(0编辑  收藏  举报
TOP