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. 自己的…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...