基于CAsyncSocket类模拟TCP网络传输之服务端

本例程对应的客户端请看https://blog.csdn.net/qq_34911636/article/details/88218891

本例程通信的流程和操作请看https://blog.csdn.net/qq_34911636/article/details/88256403

编译环境:系统:WIN7,Visual C++ 2015,建立一个ServerDlg的对话框程序

1、基于MFC创建对话框应用程序,在创建对话框应用程序时“windows套接字”选项需要打钩

二、创建ServerSocket类和ListenSocket类,两个都继承CAsyncSocket类

项目->添加类->选择MFC类->添加,如下图所示:

类名:ServerSocket类和ListenSocket类,基类选择:CAsyncSocket,点击完成,这时在项目中生成ServerSocket.h;ServerSocket.cpp和生成ListenSocket.h;ListenSocket.cpp四个文件

三、重写CAsyncSocket类的回调函数OnAccept(int nErrorCode);OnClose(int nErrorCode);OnReceive(int nErrorCode)等

打开类视图,选中左边ListenSocket类,点击右边工具栏的属性,在用鼠标点击对应的OnAccept等函数,这时在ListenSocket.h文件中生成OnAccept(int nErrorCode)函数。 

打开类视图,选中左边ServerSocket类,点击右边工具栏的属性,在用鼠标点击对应的OnReceive和OnClose等函数,这时在ServerSocket.h文件中生成OnClose(int nErrorCode);OnReceive(int nErrorCode)函数。

如下图示:

四、服务端界面的搭建,如下图所示:

 

五、添加控件的变量和处理函数

ServerDlg.h头文件中的变量:

public:
    CIPAddressCtrl m_IP;  //IP控件变量(control类型)
    CString m_Port;   //端口控件变量(value)
    CListBox m_StringWord;   //列表框控件变量(control类型)
    afx_msg void OnInternetQuit();  //“退出”按键处理函数
    afx_msg void OnStartMonitor();  //“开始监听”按键处理函数
    afx_msg void OnStopMonitor();   //“停止监听”按键处理函数
public:
    ListenSocket m_listensocket;    //网络监听类
    ServerSocket m_serversocket;    //网络服务类
    afx_msg void OnBnaboutTo();     //“关于”程序版本按键
    afx_msg void OnBnReceiveClean(); //“接收清空”按键处理函数
    CEdit m_SendWork;  //编辑框发送变量(control类型)
    afx_msg void OnBnEditClean(); //“发送清除”按键处理函数
    afx_msg void OnBnSendMessage(); //“发送”按键处理函数
    afx_msg void OnBnInternectQuit();  //“断开连接”按键处理函数
    afx_msg void OnBnSetAddress();  //“设置地址”按键处理函数
private:
    BYTE SETIP[4];
public:
    CEdit m_SetPort;  //端口控件变量(control)
    CButton m_SetAddress; //“设置地址”按键变量(control)
    CButton m_InternectQuit;  //“断开连接”按键变量(control)
    CButton m_StartMonitor;  //“开始监听”按键变量(control)
    CButton m_StopMonitor;  //“停止监听”按键变量(control)

ServerDlg.cpp文件中如下添加程序:

void CServerDlg::OnInternetQuit()  //退出程序
{
    // TODO: 在此添加控件通知处理程序代码
    m_listensocket.Close();
    CDialog::OnCancel();
}

void CServerDlg::OnStartMonitor()
{
    // TODO: 在此添加控件通知处理程序代码
    BYTE IPBYTE[4];
    CString s_IP,ipport,port;
    UINT sPort;
    UpdateData(TRUE);
    m_IP.GetAddress(IPBYTE[0], IPBYTE[1], IPBYTE[2], IPBYTE[3]);
    s_IP.Format(_T("%d.%d.%d.%d"), IPBYTE[0], IPBYTE[1], IPBYTE[2], IPBYTE[3]);
    sPort = _ttoi(m_Port);
    m_listensocket.Create(sPort,1,FD_ACCEPT,s_IP);
    m_listensocket.Listen(1);

    port.Format(_T("地址:%s"), s_IP);
    ipport.Format(_T("端口:%s"), m_Port);
    m_StringWord.AddString(_T("开始监听"));
    m_StringWord.AddString(port);
    m_StringWord.AddString(ipport);
    m_StringWord.AddString(_T("等待客户端连接......"));
    m_StringWord.SetTopIndex(m_StringWord.GetCount() + 1);

    m_IP.EnableWindow(FALSE);
    m_SetPort.EnableWindow(FALSE);
    m_SetAddress.EnableWindow(FALSE);
    m_StartMonitor.EnableWindow(FALSE);
}

void CServerDlg::OnStopMonitor()
{
    m_listensocket.Close();
    m_StringWord.AddString(_T("停止监听"));
    m_StringWord.SetTopIndex(m_StringWord.GetCount() - 1);

    m_StartMonitor.EnableWindow(TRUE);
    m_IP.EnableWindow(TRUE);
    m_SetPort.EnableWindow(TRUE);
    m_SetAddress.EnableWindow(TRUE);
    // TODO: 在此添加控件通知处理程序代码
}

void CServerDlg::OnBnSendMessage()
{
    // TODO: 在此添加控件通知处理程序代码
    //UpdateData(TRUE);
    CString sendwork,str;
    m_SendWork.GetWindowTextW(sendwork);
    if (sendwork.GetLength() != 0)
    {
        m_serversocket.Send(sendwork, 2*sendwork.GetLength());
        //m_serversocket.Send(sendwork, strlen(sendwork));
        str.Format(_T("发送:%s"), sendwork);
        m_StringWord.AddString(str);
        m_StringWord.SetTopIndex(m_StringWord.GetCount() - 1);
    }
}

void CServerDlg::OnBnaboutTo()
{
    // TODO: 在此添加控件通知处理程序代码
    CAboutDlg aboutdlg;
    aboutdlg.DoModal();
}

void CServerDlg::OnBnReceiveClean()
{
    // TODO: 在此添加控件通知处理程序代码
    m_StringWord.ResetContent();
}

void CServerDlg::OnBnEditClean()
{
    // TODO: 在此添加控件通知处理程序代码
    m_SendWork.SetWindowTextW(_T(""));
}

void CServerDlg::OnBnInternectQuit()   //断开连接
{
    // TODO: 在此添加控件通知处理程序代码
    m_serversocket.Close();
    m_StringWord.AddString(_T("断开连接"));
    m_StringWord.SetTopIndex(m_StringWord.GetCount() + 1);
}

void CServerDlg::OnBnSetAddress()
{
    // TODO: 在此添加控件通知处理程序代码
    m_IP.SetAddress(SETIP[0], SETIP[1], SETIP[2], SETIP[3]);
    m_SetPort.SetWindowTextW(_T("1035"));

}

六、ServerSocket.cpp中添加以下代码

void ServerSocket::OnReceive(int nErrorCode)
{
    // TODO: 在此添加专用代码和/或调用基类
    char Rmessage[200] = {NULL};
    CString Rstring;
    int n = Receive(Rmessage,200);
    //int stringcount = ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.GetCount();
    Rmessage[n] = _T('\0');
    Rstring.Format(_T("收到:%s"), Rmessage);
    
    //for (int i = 0; i < stringcount; i++)
    //{
    //    ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.DeleteString(0);
    //}
    ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.AddString(Rstring);
    ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.SetTopIndex(((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.GetCount() - 1);

    CAsyncSocket::OnReceive(nErrorCode);
}

void ServerSocket::OnClose(int nErrorCode)
{
    // TODO: 在此添加专用代码和/或调用基类
    int stringcount = ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.GetCount();
    for (int i = 0; i < stringcount; i++)
    {
        ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.DeleteString(0);
    }
    ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.AddString(_T("已断开连接"));
    CAsyncSocket::OnClose(nErrorCode);
}

在上述的代码中((CClientDlg*)(AfxGetApp()->m_pMainWnd))的作用;

其中AfxGetApp()获取的是应用程序类的指针,比如利用vs2010或vc6.0自动生成一个mfc工程,假设名称为Pro,若是基于单文档的程序,里面一定有CPro、CProDoc、CProView还有CMainFrame这几个类,其中,CPro代表了这个应用程序运行实例的对象,该类里面有很多成员变量,其中有不少代表窗口的变量,而m_pMainWnd正是其中的一个变量,它代表了程序的主体窗口,且它是属于CMainFrame类。MFC提供的应用程序设计理念就是文档、框架、视图  结构,这三个结构是由三个类来体现的,分别是上面提到的CProDoc(文档,代表程序的数据)、CMainFrame(框架,代表应用程序界面的框架窗口)、CProView(视图,代表应用程序的客户区界面部分),MFC基于单文档或多文档的应用程序,都是基于这个结构来实现的。而者三个结构成员是由应用程序实例的类来统一管理的,这就是上面所说的CPro类。AfxGetCpp()正是返回了这个类的指针。虽然m_pMainWnd和AfxGetCpp()的返回值都是指针,但他们的指向不同。

所以上述代码“((CClientDlg*)(AfxGetApp()->m_pMainWnd))”作用是在ClientSocket类中调用整个函数的实例,并且指向该实例的句柄,其该实例的句柄就是所看到程序运行的窗口,在通过指针引用到实例中的具体变量上,例如“ ((CClientDlg*)AfxGetApp()->m_pMainWnd)->m_Message.AddString(RWord);”就是对窗口的列表框加载字符串操作。

七、ListenSocket.cpp中添加以下代码

void ListenSocket::OnAccept(int nErrorCode)
{
    // TODO: 在此添加专用代码和/或调用基类
    int stringcount = ((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.GetCount();
    Accept(((CServerDlg*)(AfxGetApp()->m_pMainWnd))->m_serversocket);
    (((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_serversocket).AsyncSelect(FD_READ|FD_CLOSE);

    for (int i = 0; i < stringcount; i++)
    {
        (((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord).DeleteString(0);
    }
    (((CServerDlg*)AfxGetApp()->m_pMainWnd)->m_StringWord.AddString(_T(" 接收客户的一个连接请求")));

    CAsyncSocket::OnAccept(nErrorCode);
}

八、在BOOL CServerDlg::OnInitDialog()添加代码

    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    上述代码后面添加如下代码:

    SETIP[0] = 127;
    SETIP[1] = 0;
    SETIP[2] = 0;
    SETIP[3] = 1;

九、运行代码

 

 

  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值