MFC-TCP网络编程服务端-Socket

目录

1、通过Socket建立服务端:

2、UI设计:

3、代码的实现:

(1)、CListenSocket类

(2)、CConnectSocket类

(3)、CTcpServerDlg类


1、通过Socket建立服务端:

(1)、创建一个Socket对象并绑定一个端口:CListenSocket 监听Socket

(2)、通过Listen()函数,监听来自客户端的连接请求

(3)、连接请求到来之后,建立一个通信用的Socket,CConnectSocket,并且加入数组中

(4)、使用Send()、Receive()函数,接收客户端发送的数据,并遍历数组,一次转发消息

2、UI设计:

3、代码的实现:

(1)、CListenSocket类

CListenSocket的目的是等待客户端的连接请求,继承Socket类,重写Socket的OnAccept函数,创建Socket对象,连接的初始化和等待客户端连接。

CListenSocket.h中

CListenSocket(CTcpServerDlg * pdlg);//传递对话框的指针
    ~CListenSocket();
    virtual void OnAccept(int nErrorCode);//重写父类
    CTcpServerDlg *m_pMainDlg;//接收传递的对话框指针

CListenSocket.cpp中

CListenSocket::CListenSocket(CTcpServerDlg * pdlg)
{
    m_pMainDlg = pdlg; //初始化接收的对话框指针
}


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

    CSocket::OnAccept(nErrorCode);

    m_pMainDlg->ProcessPendingAccept();//对于连接函数的处理放在对话框函数中处理
}

(2)、CConnectSocket类

CConnectSocket的目的是通讯用的Socket,继承Socket类,重写Socket的OnReceive函数,数据的接收和处理以及数据的解析。

CConnectSocket.h中

CConnectSocket(CTcpServerDlg *pdlg);
    ~CConnectSocket();
    virtual void OnReceive(int nErrorCode);
    CTcpServerDlg *m_pMainDlg;

CConnectSocket.cpp中

CConnectSocket::CConnectSocket(CTcpServerDlg *pdlg)
{
    m_pMainDlg = pdlg;
}
void CConnectSocket::OnReceive(int nErrorCode)
{
    // TODO: 在此添加专用代码和/或调用基类

    CSocket::OnReceive(nErrorCode);
    m_pMainDlg->ProcessPendingRead(this);//接收消息必须要传递指针进去,调用接收函数
}

(3)、CTcpServerDlg类

1)、声明服务端用于监听的socket

//服务端声明的用于监听的socket
    CListenSocket *m_pListenSocket;

2)、声明一个CArray的对象,里面存放的CConectSocket指针

CArray<CConnectSocket*, CConnectSocket*&>m_ConnectSocketList;
    //m_ConnectSocketList是CArray的一个对象,里面放着CConnectSocket的指针,并且可以对里面的数据进行访问和修改。
    // CConnectSocket*&当数组元素被传递给函数时,使用引用方式传递元素,可以有效避免不必要的拷贝和内存开销。

3)、定义一个结构体,保存客户端的IP和Port

struct ClientAddr
{
    CString strIp;
    UINT uiPort;
};

4)、框架类的入口函数初始化监听Socket和端口号

    m_pListenSocket = new CListenSocket(this);
    //m_pListenSocket用来监听服务器的连接所以要分配内存
    m_pListenSocket->Create(8080);
    //初始化端口号
    if (!m_pListenSocket->Listen())
    {
        MessageBox(L"监听失败!");
        return FALSE;
    }

5)、实现ProcessPendingAccept()函数

主要实现监听服务器的连接,监听到了就加到列表中

CConnectSocket *pConnectSocket = new CConnectSocket(this);
    if (m_pListenSocket->Accept(*pConnectSocket))
    {
        m_ConnectSocketList.Add(pConnectSocket);
    }
    else {
        delete pConnectSocket;
    }

6)、实现ProcessPendingRead()函数

数据的接收,并且存放在buff中

TCHAR buff[4096];//存放接收到的数据

    //接收数据
    int nRead = connectSocket->Receive(buff, 4096);
    if (nRead == SOCKET_ERROR)
    {
        return;
    }

    buff[nRead] = L'\0';//接收到的数据末尾加上结束符

CString strTemp(buff);//格式化buff

把连接到的客户端IP和Port存放在结构体中

 ClientAddr clientAddr;//用来存放客户端的IP和Port

//获取连接上来的客户端的IP和端口
    connectSocket->GetPeerName(clientAddr.strIp, clientAddr.uiPort);

解析数据:加入房间enter

int i = 0;
    //解析数据
    if (strTemp.CompareNoCase(L"enter") == 0)
    {
        //通知其他客户端有人进入房间
        CString strEnterMsg;
        strEnterMsg.Format(L"系统消息:%s(%d)进入了房间", clientAddr.strIp, clientAddr.uiPort);
        for ( i;i<m_ConnectSocketList.GetSize();i++)
        {//遍历每一个客户端,并且发送消息给每个客户端。
            CConnectSocket *& tempClient = m_ConnectSocketList.ElementAt(i);
            tempClient->Send(strEnterMsg, strEnterMsg.GetLength() + 100);
        }

显示到界面

//更新界面
        SetDlgItemInt(IDC_EDIT_NUMBER, m_ConnectSocketList.GetSize());//显示当前客户端人数

        CString ALmSG;
        GetDlgItemText(IDC_EDIT_MESSAGE, ALmSG);//EDIT上显示的之前的消息
        SetDlgItemText(IDC_EDIT_MESSAGE, ALmSG + L"\r\n" + strEnterMsg);
        //显示的现在的消息加上之前的消息

解析数据:离开房间leave

//从列表中移除
        for (i;i<m_ConnectSocketList.GetSize();i++)
        {
            CConnectSocket *&temClient = m_ConnectSocketList.ElementAt(i);
            ClientAddr temClientAddr;
            temClient->GetPeerName(temClientAddr.strIp, temClientAddr.uiPort);
            if (temClientAddr.uiPort == clientAddr.uiPort && temClientAddr.strIp.Compare(clientAddr.strIp) == 0)
            {//当前移除的IP和Port如果和加入的时候存放在结构体的一样直接跳出循环删除
                break;
            }
            if (i<m_ConnectSocketList.GetSize())
            {
                m_ConnectSocketList.RemoveAt(i);
            }

发送给每一个客户端消息

//通知所有人
            CString strleaveMsg;
            strleaveMsg.Format(L"系统消息:%s(%d)进入了房间", clientAddr.strIp, clientAddr.uiPort);
            for (i; i < m_ConnectSocketList.GetSize(); i++)
            {
                CConnectSocket *& tempClient = m_ConnectSocketList.ElementAt(i);
                tempClient->Send(strleaveMsg, strleaveMsg.GetLength() + 100);
            }

更新界面

//更新界面
            SetDlgItemInt(IDC_EDIT_NUMBER, m_ConnectSocketList.GetSize());

            CString ALmSG;
            GetDlgItemText(IDC_EDIT_MESSAGE, ALmSG);
            SetDlgItemText(IDC_EDIT_MESSAGE, ALmSG + L"\r\n" + strleaveMsg);
            

发送的是普通消息

//遍历每一个客户端发出,然后更新界面即可

CString strMsg;
        strMsg.Format(L"%s(%d):%s", clientAddr.strIp, clientAddr.uiPort,strTemp);
        for (i; i < m_ConnectSocketList.GetSize(); i++)
        {
            CConnectSocket *& tempClient = m_ConnectSocketList.ElementAt(i);
            tempClient->Send(strMsg, strMsg.GetLength() + 100);
        }
        //更新界面
        SetDlgItemInt(IDC_EDIT_NUMBER, m_ConnectSocketList.GetSize());

        CString ALmSG;
        GetDlgItemText(IDC_EDIT_MESSAGE, ALmSG);
        SetDlgItemText(IDC_EDIT_MESSAGE, ALmSG + L"\r\n" + strMsg);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/138423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch中实际操作细节点

ElasticSearch中的细节点 文章目录 ElasticSearch中的细节点1、提示&#xff1a;1.1 ElasticSearch相关文档&#xff1a;1.2 Kibana的常用快捷键1.3 kibana的注释方式 2、term与terms的用法以及区别3、ElasticSearch中"index":"false","doc_values&qu…

大数据治理——为业务提供持续的、可度量的价值(一)

目录 大数据治理——为业务提供持续的、可度量的价值... 1 概述... 2 大数据治理系列... 2 第一部分&#xff1a;大数据治理统一流程模型概述和明确元数据管理策略... 2 第二部分&#xff1a;元数据集成体系结构... 15 第三部分&#xff1a;实施元数据管理... 25 第四部…

顺序图——画法详解

百度百科的定义&#xff1a; 顺序图是将交互关系表示为一个二维图。纵向是时间轴&#xff0c;时间沿竖线向下延伸。横向轴代表了在协作中各独立对象的类元角色。类元角色用生命线表示。当对象存在时&#xff0c;角色用一条虚线表示&#xff0c;当对象的过程处于激活状态时&…

AI机器人小奥,学习不再填鸭

在这个充满科技魅力的时代&#xff0c;一款专为孩子学习量身打造的AI机器人“小奥”正式与大家见面&#xff01; 它是一款集全球领先的人工智能、语音识别、语义理解、情感陪伴为一体的高科技教育产品&#xff0c;旨在帮助孩子提高学习兴趣、拓宽知识面&#xff0c;以科技创新助…

uniapp使用v-for页面不刷新解决办法

项目场景&#xff1a; 做一个项目&#xff0c;v-for循环数据库数据&#xff0c;使用uni-load-more&#xff0c;结果发现... DOM中的列表却没有更新 解决方案&#xff1a; 根据网上教程&#xff0c;加了一个触底函数onReachBottom&#xff0c;结果发现无论如何也更新不了DOM中…

人工智能基础——Python:Pillow与图像处理

人工智能的学习之路非常漫长&#xff0c;不少人因为学习路线不对或者学习内容不够专业而举步难行。不过别担心&#xff0c;我为大家整理了一份600多G的学习资源&#xff0c;基本上涵盖了人工智能学习的所有内容。点击下方链接,0元进群领取学习资源,让你的学习之路更加顺畅!记得…

uniapp 实现路线规划

UniApp是一个跨平台的应用开发框架&#xff0c;可以帮助开发者快速地在多个平台上构建应用程序。其中&#xff0c;实现路线规划是一个常见的需求&#xff0c;特别是对于地图类应用或者出行类应用来说&#xff0c;路线规划功能是非常重要的。 首先引入QQMapWX&#xff1b; impo…

经典算法(查找与排序)

查找 顺序查找 顺序查找&#xff08;Linear Search&#xff09;是一种在有序数组中查找目标元素的基本算法。它的时间复杂度为 O(n)&#xff0c;适用于查找少量数据。顺序查找的基本思想是从数组的第一个元素开始&#xff0c;逐个与待查找的元素进行比较&#xff0c;直到找到…

AMD64内存属性详解

本文参考文档为AMD64 Architecture Programmer’s Manual Volume 2: System Programming&#xff0c;版本号3.41&#xff0c;这不是对原英文文档的翻译&#xff0c;但是所有内容的排版都是根据原手册的排版来的&#xff0c;如有与官方文档冲突的内容&#xff0c;以官方文档为准…

Ubuntu 配置 Github 的 SSH keys

先进入已有的 Git 目录或使用新建的一个 Git 仓库下。 设置 Github 用户名和邮箱&#xff1a; $ git config --global user.name [Github用户名] $ git config --global user.email [Github认证邮箱]生成 SSH 密钥文件&#xff1a; $ ssh-keygen -t rsa -C [Github认证邮箱]…

Jmeter_逻辑控制器

逻辑控制器 控制取样器执行顺序的组件实现(分支 循环) 分类 1、如果(if) 控制器 分支实现 2、forEach控制器 循环往复实现 3、循环控制器 循环往复实现 如果(if) 控制器 需求1:测试计划中定义一个 http 请求访问百度&#xff0c;但是该请求不是无条件执行的&#xff0c;…

基于ssm的校园快递物流管理系统(java+jsp+ssm+javabean+mysql+tomcat)

博主24h在线&#xff0c;想要源码文档部署视频直接私聊&#xff0c;9.9拿走&#xff01; 基于javawebmysql的ssm校园快递物流管理系统(javajspssmjavabeanmysqltomcat) 运行环境&#xff1a; Java≥8、MySQL≥5.7、Tomcat≥8 开发工具&#xff1a; eclipse/idea/myeclipse/s…

2023年云计算发展趋势浅析

​​​​​​​ 云计算的概念 云计算是一种通过互联网提供计算资源和服务的模式。它允许用户通过网络访问和使用共享的计算资源&#xff0c;而无需拥有或管理这些资源的物理设备。云计算的核心理念是将计算能力、存储资源和应用程序提供给用户&#xff0c;以便随时随地根据需要…

【JS 高级之手写原理系列】学习笔记共 15 篇(完结)

这是我在 b 站上面学习的一门课程&#xff0c;个人学习笔记地址&#xff1a;https://github.com/kaimo313/javascript-advanced-handwriting-principles-series 01 # 手写 new 的原理02 # 手写 instanceof 的原理03 # 手写 call04 # 手写 apply05 # 手写 bind06 # 手写 map 方…

关于变电站综合自动化系统的案例应用分析-安科瑞 蒋静

摘 要&#xff1a;变电站综合自动化系统是将变电站内的二次设备经过功能的组合和优化设计&#xff0c;利用先进的计算机技术、通信技术、信号处理技术&#xff0c;实现对全变电站的主要设备和输、配电线路的自动监视、测量、控制、保护、并与上级调度通信的综合性自动化功能。 …

前端小技巧: TS实现EventBus自定义事件

关于EventBus事件总线 事件总线&#xff0c;实现 on, once, emit, off on, once 是注册函数&#xff0c;存储起来emit时找到对应的函数&#xff0c;执行off找到对应的函数&#xff0c;从对象中删除 注意 区分on和onceon绑定的事件可连续执行&#xff0c;除非offonce绑定的函数…

POD创建与删除简单描述

创建一个 Pod 的过程可以分为以下几个步骤&#xff1a; 用户使用 kubectl create 命令或 YAML 文件向 API 服务器发送创建 Pod 的请求。API 服务器将请求转换为 Kubernetes 的内部对象&#xff0c;并将 Pod 的状态设置为 Pending。调度器根据 Pod 的资源需求和节点的资源情况&…

linux 内存查看方法:meminfo\maps\smaps\status 文件解析

linux 下面查看内存有多种渠道&#xff0c;比如通过命令 ps ,top,free 等&#xff0c;比如通过/proc系统&#xff0c;一般需要比较详细和精确地知道整机内存/某个进程内存的使用情况&#xff0c;最好通过/proc 系统&#xff0c;下面介绍/proc系统下内存相关的几个文件 单个进程…

4.4.2 结构可以将 string类作为成员吗

// structure template { }; 4.4.2 结构可以将 string类作为成员吗 可以将成员name指定为string类对象而不是字符数组吗?即可以像下面这样声明结构吗? #include <string> struct inflatable std :: string name; float volume; double price; 大体上说,答案是肯定的。实…

go语言 | 图解反射(一)

反射 反射是指在程序运行期对程序本身进行访问和修改的能力 变量的内在机制 变量包含类型信息和值信息 var arr [10]int arr[0] 10 类型信息&#xff1a;是静态的元信息&#xff0c;是预先定义好的 值信息&#xff1a;是程序运行过程中动态改变的 反射的使用 reflect包封…