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. 自己的…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
