MFC网络通信-Udp服务端
目录
1、UI的布局
2、代码的实现:
(1)、自定义的子类CServerSocket
(2)、重写OnReceive事件
(3)、在CUdpServerDlg类中处理
(4)、在OnInitDialog函数中
(5)、实现自定义函数ProcessPendingRead()处理接收到的数据
(6)、加入新客户的消息先进性判断是否位enter
(7)、加入的新消息如果是leave
(8)、普通信息
1、UI的布局

添加一个CServerSocket类继承于CSocket
2、代码的实现:
(1)、自定义的子类CServerSocket
所有的显示应该显示在框架中,在构造函数传入一个框架的指针然后进行初始化
class CUdpServerDlg;//声明一下dlg类
public:
CServerSocket(CUdpServerDlg* pdlg);//所有的操作显示在dlg上面
~CServerSocket();
private:
CUdpServerDlg *m_pMainDlg;//指针来接收
CServerSocket::CServerSocket(CUdpServerDlg* pdlg)//传递的消息统一放在对话框中处理,所以初始化传递一个对话框指针
{
this->m_pMainDlg = pdlg;
}
(2)、重写OnReceive事件
(父类的OnReceive是纯虚函数,如果有数据可读就会调用该方法)
protected:
virtual void OnReceive(int nErrorCode);//重写onReceive()方法,如果有数据可读就会调用该方法
//在WINSOCKET父类中有这个纯虚函数来接收数据
//有数据可读就会调用这个纯虚函数
void CServerSocket::OnReceive(int nErrorCode)
{
CSocket::OnReceive(nErrorCode);
/*该行代码的作用是确保底层的数据接收和处理机制正常运行,并在此基础上执行自定义的数据处理逻辑。*/
m_pMainDlg->ProcessPendingRead();//消息处理统一放在对话框
}
(3)、在CUdpServerDlg类中处理
struct ClientAddr//自定义结构体存放IP和端口号
{
CString strIP;
UINT inPort;
};
CServerSocket *m_pServerSocket;
CArray<ClientAddr,ClientAddr&>m_ClientAddList;//客户端发送的所有消息
/*,m_ClientAddList是一个包含ClientAddr类型对象的数组,可以使用Add()方法向其中添加元素,使用GetAt()方法访问已添加的元素。这个数组被用来存储客户端连接的地址信息等数据。*/
void ProcessPendingRead();
(4)、在OnInitDialog函数中
m_pServerSocket = new CServerSocket(this);在当前对话框中需要使用到通信(SOCKET),所以在堆区创建一个CServerSocket的对象,并且还要这个对象和当前窗口相关联,然后用一个m_pServerSocket指针指向新建的对象。
m_pServerSocket->Create(8080, SOCK_DGRAM);//用于创建一个 UDP 套接字,并将其绑定到本地 IP 地址和指定的端口号(这里是 8080)上。
(5)、实现自定义函数ProcessPendingRead()处理接收到的数据
初始化接收数据数组和客户端结构体对象
TCHAR buffer[4096];//接收数据的数组
ClientAddr clietAddr;//客户端结构体对象
判断读取的内容的是否有效
int nRead = m_pServerSocket->ReceiveFrom(buffer, 4096, clietAddr.strIP, clietAddr.inPort);//接收数据的字节数nRead
//缓冲区地址,接收数据大小,客户端的IP,客户端的端口
if (nRead == SOCKET_ERROR)//如果读出错
{
return;
}
如果内容有效字符串结尾加上\0,并且转换类型位CString类型
buffer[nRead] = L'\0';
//在接收到的数据后面加上结束符(索引0开始,所以nRead代表最后一位加1)
CString strTemp(buffer);//char *类型的buffer转成CString类型的strTemp,代表接收到的内容。
strTemp是接收到的消息,消息又分为三种,加入新客户,删除客户,还有就是普通消息
(6)、加入新客户的消息先进性判断是否位enter
if (strTemp.CompareNoCase(_T("enter"))==0)
/*比较 strTemp 和 "enter" 是否相等,不区分大小写。如果相等,则返回 0,否则返回一个非零值*/
在条件下我们将客户加入到列表中
/把新的客户加入到列表中
m_ClientAddList.Add(clietAddr);
通知其它客户端有用户加入
首先加入的信息需要规范一下
CString strEnterMsg;
strEnterMsg.Format(_T("系统消息:%s(%d)进入了房间"), clietAddr.strIP, clietAddr.inPort);
通知其他客户端
for (i = 0;i<m_ClientAddList.GetSize();i++)//通知所有的客户端
{
ClientAddr& tempClient = m_ClientAddList.ElementAt(i);//获取所有的客户端
m_pServerSocket->SendTo(strEnterMsg, strEnterMsg.GetLength() + 1000, tempClient.inPort, tempClient.strIP);//发送消息
}
控件上的显示更新(人数的更新还有内容的更新)
SetDlgItemInt(IDC_EDIT_NUMBER, m_ClientAddList.GetSize());//当前人数在文本上设置
//之前的消息可能存在,需要拿出来放在alMsg的后面
CString alMsg;
GetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg);//取消消息到alMsg
SetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg + _T("\r\n") + strEnterMsg);//将新的消息叠加到alMsg后面
(7)、加入的新消息如果是leave
if (strTemp.CompareNoCase(_T("leave")) == 0)
//离开房间
从列表中遍历寻找要删除的用户
//列表中移除用户
for (i = 0;i<m_ClientAddList.GetSize();i++)
{
ClientAddr& tempClient = m_ClientAddList.ElementAt(i);//遍历每一个
if (tempClient.inPort == clietAddr.inPort&&tempClient.strIP.Compare(clietAddr.strIP) == 0)
{
break;
//遍历找到了要移除的端口号和IP都相等的tempClient,break
}
}
一旦找到用户break,然后删除用户
if (i<m_ClientAddList.GetSize())//如果遍历没完就说明找到了。
{
m_ClientAddList.RemoveAt(i);//移除
}
格式化发送的消息
CString strLeaveMsg;
strLeaveMsg.Format(_T("通知消息:%s(%d)离开了房间"), clietAddr.strIP, clietAddr.inPort);//通知的内容
遍历发送所有的客户端
for (i = 0; i < m_ClientAddList.GetSize(); i++)//通知每一个客户端有用户离开了
{
ClientAddr& tempClient = m_ClientAddList.ElementAt(i);
m_pServerSocket->SendTo(strLeaveMsg, strLeaveMsg.GetLength() + 1000, tempClient.inPort, tempClient.strIP);
}
更新控件上的内容
SetDlgItemInt(IDC_EDIT_NUMBER, m_ClientAddList.GetSize());//更新当前人数
CString alMsg;
GetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg);
SetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg + _T("\r\n") + strLeaveMsg);//更新消息
(8)、普通信息
else//普通的聊天信息
{
CString strMsg;
strMsg.Format(_T("%s(%d):%s"), clietAddr.strIP, clietAddr.inPort,strTemp);//格式化普通聊天信息的内容
for (i = 0; i < m_ClientAddList.GetSize(); i++)
{ //转发所有的人消息
ClientAddr& tempClient = m_ClientAddList.ElementAt(i);
m_pServerSocket->SendTo(strMsg, strMsg.GetLength() + 1000, tempClient.inPort, tempClient.strIP);
}
CString alMsg;
GetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg);
SetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg + _T("\r\n") + strMsg);//更新聊天框的内容
}
(3)、优化处理
初始化默认服务端的端口和IP在框架的入口函数
//设置服务端默认的端口和IP
SetDlgItemText(IDC_EDIT_SERVER_IP, L"127.0.0.1");
SetDlgItemText(IDC_EDIT_SERVER_PORT, L"8080");
初始化按钮的一些状态
没有加入房间,发送按钮和退出按钮都不能点击
//设置按钮初始化状态
GetDlgItem(IDC_BUTTON_OUT)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);
初始化发送消息的EDIT只读,服务端IP和PORT可以修改
GetDlgItem(IDC_EDIT_SEND_MESSAGE)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERVER_IP)->EnableWindow(TRUE);
GetDlgItem(IDC_EDIT_SERVER_PORT)->EnableWindow(TRUE);
加入房间之后重新设置按钮的状态
//设置按钮文本框的状态
//设置按钮初始化状态
GetDlgItem(IDC_BUTTON_OUT)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(TRUE);((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(TRUE);
离开房间重新设置按钮的状态
GetDlgItem(IDC_BUTTON_OUT)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(FALSE);
重写框架类的关闭窗口函数
实现关闭窗口之后调用离开房间按钮事件。
BOOL CUdpClientDlg::DestroyWindow()
{
// TODO: 在此添加专用代码和/或调用基类
if (m_bEnterRoom)
{
OnBnClickedButtonOut();
}return CDialogEx::DestroyWindow();
}
相关文章:
MFC网络通信-Udp服务端
目录 1、UI的布局 2、代码的实现: (1)、自定义的子类CServerSocket (2)、重写OnReceive事件 (3)、在CUdpServerDlg类中处理 (4)、在OnInitDialog函数中 ࿰…...
最简单且有效的msvcp140.dll丢失的解决方法,有效的解决msvcp140.dll丢失
在我们使用电脑的过程中,有时会遇到一些令人困扰的问题,如msvcp140.dll文件丢失。对于许多不熟悉这方面技术的小伙伴来说,遇到msvcp140.dll丢失的问题可能会觉得棘手。其实这是一个很常见的问题,并且解决起来并不复杂。接下来将给…...
HBase理论与实践-基操与实践
基操 启动: ./bin/start-hbase.sh 连接 ./bin/hbase shell help命令 输入 help 然后 <RETURN> 可以看到一列shell命令。这里的帮助很详细,要注意的是表名,行和列需要加引号。 建表,查看表,插入数据&#…...
内存管理设计精要
系统设计精要是一系列深入研究系统设计方法的系列文章,文中不仅会分析系统设计的理论,还会分析多个实际场景下的具体实现。这是一个季更或者半年更的系列,如果你有想要了解的问题,可以在文章下面留言。 持久存储的磁盘在今天已经不…...
Java——StringBuffer与StringBuilder的区别
Java——StringBuffer与StringBuilder的区别 StringBuffer和StringBuilder是Java中用于处理字符串的两个类,它们之间的主要区别在于线程安全性和性能方面。 1. 线程安全性: StringBuffer:StringBuffer 是线程安全的,所有的公共方…...
基于深度学习的菠萝与果叶视觉识别及切断机构设计
收藏和点赞,您的关注是我创作的动力 文章目录 概要 一、课题内容二、总体方案确定2.1 方案选择2.2 菠萝的视觉识别流程2.3 菠萝果叶切断机构设计流程 三 基于深度学习的菠萝检测模型3.1 卷积神经网络简介3.2 YOLO卷积神经网络3.3 图像采集与数据制作3.4 数据训练与…...
springboot整合七牛云oss操作文件
文章目录 springboot整合七牛云oss操作文件核心代码(记得修改application.yml配置参数⭐)maven依赖QiniuOssProperties配置类UploadControllerResponseResult统一封装响应结果ResponseType响应类型枚举OssUploadService接口QiniuOssUploadServiceImpl实现…...
跨国传输的常见问题与对应解决方案
在今天的全球化时代,跨国数据传输已经成为一个不可或缺的需求。不论是个人还是企业,都需要通过网络将文件或数据从一个国家传输到另一个国家,以实现信息共享、协作、备份等目的。然而,跨国数据传输并不是一项容易的任务࿰…...
Git(七).git 文件夹瘦身,GitLab 永久删除文件
目录 一、问题背景二、问题复现2.1 新建项目2.2 上传大文件2.3 上传结果 三、解决方案3.1 GitLab备份与还原1)备份2)还原 3.2 删除方式一:git filter-repo 命令【推荐】1)安装2)删除本地仓库文件3)重新关联…...
多线程锁的升级原理是什么
在 Java 中,锁共有 4 种状态,级别从低到高依次为:无状态锁,偏向锁,轻量级锁和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。 多线程锁锁升级过程 如下图所示 多线程锁的升级过程…...
金山文档轻维表之删除所有行记录
目前脚本文档里面的只有删除行记录功能,但是需要指定ID值,不能实现批量删除,很多人反馈但是官方无回应,挺奇怪的 但是批量删除的需求我很需要,最后研究了一下,还是挺容易实现的 测试: 附上脚本…...
站坑站坑站坑站坑站坑
站坑站坑站坑站坑站坑站坑站坑...
在Vue中,你可以使用动态import()语法来动态加载组件
在Vue中,你可以使用动态import()语法来动态加载组件。动态导入允许你在需要时异步加载组件,这样可以提高应用程序的初始加载性能。 下面是一个使用动态导入加载组件的示例: <template> <div> <button click"loadComp…...
金蝶云星空表单插件获取日期控件判空处理(代码示例)
文章目录 金蝶云星空表单插件获取日期控件判空处理C#实现 金蝶云星空表单插件获取日期控件判空处理 C#实现 DateTime? deliveryDate (DateTime?)this.View.Model.GetValue("FApproveDate");//审核日期long leadtime 20;//天数if (!deliveryDate.IsNullOrEmpty()…...
通过xshell传输文件到服务器
一、user is not in the sudoers file. This incident will be reported. 参考链接: [已解决]user is not in the sudoers file. This incident will be reported.(简单不容易出错的方式)-CSDN博客 简单解释下就是: 0、你的root需要设置好密码 sudo …...
centos7.9编译安装python3.7.2
联网环境下编译安装python3.7.2,不联网则需要配置cnetos7.9离线源 下载解压软件包 [rootlocalhost ~]# tar -xf Python-3.7.3.tar.gz [rootlocalhost ~]# ls anaconda-ks.cfg Python-3.7.3 Python-3.7.3.tar.gz [rootlocalhost ~]# [rootlocalhost ~]# cd Pytho…...
【教3妹学编程-算法题】2913. 子数组不同元素数目的平方和 I
-----------------第二天------------------------ 面试官 : 好的, 我们再来做个算法题吧。平时工作中会尝试用算法吗, 用到了什么数据结构? 3妹 : 有用到, 用到了 bla bla… 面试官 : 好的, 题目是这样的࿱…...
是否会有 GPT-5 的发布?
本心、输入输出、结果 文章目录 是否会有 GPT-5 的发布?前言围绕 GPT-5 的信息OpenAI 期待增长GPT-5 - 到底是真的在训练,还是一个虚构的故事Sam Altman字里行间包含的信息我们在什么时候可以期待 GPT-5 的发布GPT-5 预计将在哪些方向努力GPT-5 在听觉领域GPT-5 在视频处理领…...
使用 Selenium Python 检查元素是否存在
像 Selenium 这样的自动化工具使我们能够通过不同的语言和浏览器自动化 Web 流程并测试应用程序。 Python 是它支持的众多语言之一,并且是一种非常简单的语言。 它的Python客户端帮助我们通过Selenium工具与浏览器连接。 Web 测试对于开发 Web 应用程序至关重要&am…...
const迭代器与模板构造函数
在自己实现C中list的时候,当实现const迭代器的时候,发现报错了,一直思考到现在 才发现是一个,很简单的问题,但是也让我有了一点感受,我在这里给大家分享一下。文章目录 1.当时遇到的问题2.解决方法3. 自己的…...
Seraphine终极指南:英雄联盟免费智能助手,5分钟提升排位胜率15%
Seraphine终极指南:英雄联盟免费智能助手,5分钟提升排位胜率15% 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine 还在为英雄联盟排位赛中的战绩查询和BP决策烦恼吗?Seraphin…...
像素风机甲对战小游戏HTML
先放效果图🎮 游戏玩法设计功能说明: 双人对战:两个玩家在同一键盘上对战 移动系统:左右移动 跳跃(带重力物理) 攻击系统: 近战攻击,有冷却时间和范围判定 防御系统:…...
【AI入门知识点】Skills 是什么?终于有人把 Skills、Function Calling、MCP 讲明白了
为什么现在 AI 会查天气?为什么 AI 能读 Excel、操作浏览器、发邮件?为什么很多人说:未来 AI 拼的不是谁更聪明,而是谁 Skills 更多?很多刚学 AI 的人。都会被几个词搞晕:SkillsFunction CallingMCP看起来都…...
专栏导读:为什么需要从 MM 理解 HMM
一个真实的困境 假设你是一个 GPU 计算框架的开发者。用户写了这样一段代码: float *data malloc(1GB); // ... 填充数据 ... gpu_kernel<<<grid, block>>>(data); // 希望 GPU 直接访问 data在传统编程模型下,这不可能工作——GPU …...
CANN/asc-devkit Ascend C矢量压缩API
asc_squeeze 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://gitcode.co…...
机器学习之逻辑回归算法
一、逻辑回归简介 1. 定义 逻辑回归(Logistic Regression)是一种有监督学习算法,主要用于解决二分类问题的统计学习方法。尽管名字中带有“回归”,但它实际上是一种分类算法。 大白话解释 逻辑回归就是一种“做判断题”的算法&…...
工具调用优化:减少API延迟对Agent性能的影响
《工具调用优化全指南:彻底解决API延迟拖累大模型Agent性能的痛点》 副标题:从原理到落地,覆盖缓存、并行、调度、轻量化改造全链路可复现方案 第一部分:引言与基础 1.1 摘要/引言 你有没有遇到过这种场景:辛辛苦苦开发的智能Agent功能非常强大,能查订单、搜资料、算数…...
创业团队如何利用Taotoken统一管理多个AI模型API以控制开发成本
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 创业团队如何利用Taotoken统一管理多个AI模型API以控制开发成本 对于资源有限的创业团队而言,在业务开发中引入大模型能…...
制造业的AI智能体,为什么“部署方式”比“功能有多强”更关键?
和几位制造业IT负责人的交流中,有一个现象值得关注:他们最担心的不是AI智能体“能不能用”,而是“怎么部署”。 这和前两年的讨论方向明显不同。2024年前后,行业还在争论AI智能体到底有没有用、能在哪些场景落地。到了2026年&…...
从文件上传到 RAG 检索:真正看懂了一个 AI 项目的知识库链路
一、前言:今天不是单独学一个知识点,而是串起了一条完整链路 今天继续分析 AI 项目中的 RAG 模块时,我发现自己之前对“文件上传”“文件切片”“向量化”“召回”“大模型回答”这些概念,虽然都单独听过,但真正放到项…...
