• MFC-TCP网络编程客户端-Socket


    目录

    1、客户端创建流程:

    2、UI设计:

    3、代码实现:

    (1)、ConnectSocket中重写OnReceive函数接收信息

    (2)、框架类入口函数初始化

    (3)、加入房间功能实现

    (4)、离开房间功能实现

    (5)、发送消息功能实现

    (6)、OnPendingRead函数实现

    4、最终运行结果:


    1、客户端创建流程:

    (1)、创建一个Socket对象并且自动绑定一个端口。

    (2)、调用Connect()函数,建立一个到服务端的连接。

    (3)、发送一个特殊消息进入房间enter。

    (4)、使用Receive()函数,Send函数收发数据。

    (5)、发送一个特殊消息退出房间leave。

    2、UI设计

    3、代码实现:

    (1)、ConnectSocket中重写OnReceive函数接收信息

    CConnectSocket(CTcpClientDlg *pdlg);//框架类的指针,目的处理函数得放在框架中
        ~CConnectSocket();
        
        CTcpClientDlg * m_pMainDlg;
        virtual void OnReceive(int nErrorCode);

    void CConnectSocket::OnReceive(int nErrorCode)
    {
        // TODO: 在此添加专用代码和/或调用基类

        CSocket::OnReceive(nErrorCode);
        m_pMainDlg->OnPendingRead();//处理函数在框架中,因为显示在对话框中
    }

    (2)、框架类入口函数初始化

       //初始化服务端的IP,Port放在显示在UI

        SetDlgItemText(IDC_EDIT_SERVER_IP, L"127.0.0.1");
        SetDlgItemText(IDC_EDIT_SERVER_PORT, L"8080");

    //设置各个按钮控件的状态

        GetDlgItem(IDC_BUTTON_ENTER_ROOM)->EnableWindow(TRUE);
        GetDlgItem(IDC_BUTTON_LEAVE_ROOM)->EnableWindow(FALSE);
        GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);

    //设置EDIT控件的只读或者可写

        ((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(TRUE);
        ((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(TRUE);
        ((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(TRUE);

    (3)、加入房间功能实现

    随机分配一个空闲的端口号

        // 创建tcp套接字并且绑定一个自动分配的端口号
            m_Pconnect = new CConnectSocket(this);
        m_Pconnect->Create();

    把本地的IP和Port显示在UI

    //获取本地的端口和IP,并显示在UI
        CString strlocalIP;
        UINT uilocalPort;
        m_Pconnect->GetSockName(strlocalIP, uilocalPort);
        SetDlgItemText(IDC_EDIT_LOCAL_IP, strlocalIP);
        SetDlgItemInt(IDC_EDIT_LOCAL_PORT, uilocalPort);

    补充:建立TCP通讯的条件:

    服务端和客户端的俩个端口得是空闲端口,客户端指定发送信息的IP地址,客户端在指定的IP上等待连接,同时还得有TCP\IP协议。

    调用Connect连接服务端和客户端

        //调用connect函数连接服务端
        CString strServerIP;
        UINT uiServerPort;//服务端的IP和Port
        GetDlgItemText(IDC_EDIT_SERVER_IP, strServerIP);
        uiServerPort = GetDlgItemInt(IDC_EDIT_SERVER_PORT);

        if (!m_Pconnect->Connect(strServerIP, uiServerPort))
        {
            MessageBox(L"连接服务端失败");
            return;
        }

    连接成功说明一个客户端加入房间

    CString strEnterRoom = L"enter";
        m_Pconnect->Send(strEnterRoom, strEnterRoom.GetLength() + 100);
        m_bEnterRoom = TRUE;

    界面的改变

    GetDlgItem(IDC_BUTTON_ENTER_ROOM)->EnableWindow(FALSE);
        GetDlgItem(IDC_BUTTON_LEAVE_ROOM)->EnableWindow(TRUE);
        GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(TRUE);

        ((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(FALSE);

    (4)、离开房间功能实现

       CString strleaveRoom = L"leave";
        m_Pconnect->Send(strleaveRoom, strleaveRoom.GetLength() + 100);
        m_bEnterRoom = FALSE;

        GetDlgItem(IDC_BUTTON_ENTER_ROOM)->EnableWindow(TRUE);
        GetDlgItem(IDC_BUTTON_LEAVE_ROOM)->EnableWindow(FALSE);
        GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);

        ((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(TRUE);
        ((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(FALSE);
        ((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(FALSE);

    (5)、发送消息功能实现

    发送消息给客户端

        // TODO: 在此添加控件通知处理程序代码
        CString strMsg;
        GetDlgItemText(IDC_EDIT_SEND_MESSAGE, strMsg);
        m_Pconnect->Send(strMsg, strMsg.GetLength() + 100);

        SetDlgItemText(IDC_EDIT_SEND_MESSAGE, L"");//将文本框清空方便下次输入

    (6)、OnPendingRead函数实现

    接收从客户端分发的消息

        TCHAR buff[4096];
        int nRead =m_Pconnect->Receive(buff, 4096);
        if (nRead == SOCKET_ERROR)
        {
            return;
        }
        buff[nRead] = L'\0';
        CString charMsg(buff);

        CString alMsg;
        GetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg);
        SetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg + L"\r\n" + charMsg);

    4、最终运行结果:

  • 相关阅读:
    【Flutte】【widget】drawer 抽屉快速实现
    [springboot源码分析]-Conditional
    Jenkins 执行job通知飞书机器人
    【单目3D目标检测】SMOKE + MonoFlex 论文解析与代码复现
    凉鞋的 Godot 笔记 101. Hello Godot!
    TiDB Lightning 错误处理功能
    计算机毕业设计Python+Spark+PyTroch游戏推荐系统 游戏可视化 游戏爬虫 神经网络混合CF推荐算法 协同过滤推荐算法 steam 大数据
    ZYNQ UltraScale MPSOC,使用PL端AXI_UART16550IP核,且在PS端控制下实现RS485通信-----轮询方式
    基于FPGA的FIR数字滤波器设计(quartus和vivado程序都有)。
    跨域问题?如何解决?
  • 原文地址:https://blog.csdn.net/qq_59328991/article/details/134292376