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.hqwc.cn/news/164777.html

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

相关文章

3.5、Linux:命令行git的使用

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 在Linux Centos7.6下安装git yum -y install git 注册一个gitee账号 进去注册就好&#xff0c;记住自己的用户名和密码。 创建一个仓库 点击复制&#xff0c;接着就可以在Linux上使用了 git clone git clone 刚才复制的地…

机器人控制——C++ HSM状态机基础知识

本章将向您介绍使用HSM的基本知识。为了简单起见&#xff0c;我们将在这里学习如何编写单层次&#xff08;也称为平面&#xff09;状态机&#xff0c;并在下一章中介绍层次状态机。 让我们从我们可以编写的最简单的状态机开始。 // simplest_state_machine.cpp#include "…

茶楼计时茶室时钟计费系统,佳易王共享茶室收银计时收费管理系统软件下载

茶楼计时茶室时钟计费系统&#xff0c;佳易王共享茶室收银计时收费管理系统软件下载 软件功能&#xff1a; 1、计时计费功能&#xff1a;可以按单价计费&#xff0c;可以按时间段计费。时间显示直观&#xff0c;每个桌子用时一目了然。每个桌子价格可以设置相同也可以不相同。…

kubernetes资源监控

目录 一、资源限制 1、limitrange 2、ResourceQuota 二、metrics-server 三、图形化监控和代码行监控 1、dashboard 2、k9s 四、hpa 一、资源限制 Kubernetes采用request和limit两种限制类型来对资源进行分配。request(资源需求)&#xff1a;即运行Pod的节点必须满足运…

关于卷积神经网络的填充(padding)

认识填充 &#xff08;padding&#xff09; 随着卷积层数的加深&#xff0c;输出进一步缩小&#xff0c;那么最终会导致输出很快就只剩下1∗1的数组&#xff0c;这也就没办法继续计算了&#xff0c;所以提出了填充的方法来方便网络的进一步加深。 其实填充的原因有两点&#xf…

JavaWeb Day05 前后端请求响应与分层解耦

目录 一、请求与响应 &#xff08;一&#xff09;请求的参数接收 ①数组参数 ②集合参数 ③日期参数 ④json参数 ⑤路径参数 总结 &#xff08;二&#xff09;响应 ①简单文本text ②数组 ③列表 ④同一响应数据格式 ⑤总结 二、三层架构与分层解耦 &#xff0…

宋浩高等数学笔记(一)函数与极限

b站宋浩老师的高等数学网课&#xff0c;全套笔记已记完&#xff0c;不定期复习并发布更新。 章节顺序与同济大学第七版教材所一致。 目录 1.1映射与函数 1.2数列的极限 1.3函数的极限 1.4无穷小和无穷大 1.5极限运算准则 1.6极限存在准则and两个重要极限 1.7无穷小 1…

【数组】【快慢指针】Leetcode 27 移除元素

【数组】【快慢指针】Leetcode 27 移除元素 解法1 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法1 时间复杂度O(N) 空间复杂度O(1) class Solution {public int removeElement(int[] nums, int val) {// 快慢指针…

【UE4】UE编辑器乱码问题

环境&#xff1a;UE4.27、vs2019 如何解决 问题原因&#xff0c;UE的编码默认是UTF-8&#xff0c;VS的默认编码是GBK 通过"高级保存选项" 直接修改VS的 .h头文件 的 编码 为 UTF-8 步骤1. 步骤2. 修改编码后&#xff0c;从新编译&#xff0c;然后就可以解决编辑器…

在MacBook上实现免费的PDF文件编辑

之前我想对PDF文件进行简单处理&#xff08;比如删页面、添空白页、调整页面顺序&#xff09;&#xff0c;要么是开wps会员【花钱贵】&#xff0c;下载&#xff08;盗版&#xff09;Adobe Acrobat【macOS不好下载】&#xff0c;要么用福昕阅览器登陆学生账号&#xff08;学校买…

Jmeter接口自动化测试操作流程

在企业使用jmeter开展实际的接口自动化测试工具&#xff0c;建议按如下操作流程&#xff0c; 可以使整个接口测试过程更规范&#xff0c;更有效。 接口自动化的流程&#xff1a; 1、获取到接口文档&#xff1a;swagger、word、excel ... 2、熟悉接口文档然后设计测试用例&am…

第二证券:消费电子概念活跃,博硕科技“20cm”涨停,天龙股份斩获10连板

消费电子概念7日盘中再度拉升&#xff0c;到发稿&#xff0c;博硕科技“20cm”涨停&#xff0c;光大同创、波长光电涨超10%&#xff0c;易德龙、向阳科技、得润电子、天龙股份、同兴达等涨停。 博硕科技强势涨停&#xff0c;公司昨日在接受安排调研时表明&#xff0c;公司从上…