C++打造局域网聊天室第九课: 客户端队列及其处理线程
文章目录
- 前言
- 一、添加客户端队列的参数初始化
- 二、相关函数
- 总结
前言
C++打造局域网聊天室第九课: 客户端队列及其处理线程
一、添加客户端队列的参数初始化
在Server.cpp的 ListenThreadFunc()函数内的其他操作处实现客户端队列的添加。

首先进行部分参数的初始化
CClientitem tItem; //定义一个客户端结点
tItem.m_Socket = accSock; //客户端的socket即为accept函数返回的accSock
tItem.m_surlp = inet_ntoa(clientAddr.sin_addr); // 客户端的IP包含在clientAddr结构中。inet_ntoa()函数将网络字节顺序的Ip转化为本机格式的字符串(192.192.1.1)
tItem.m_pMainWnd = pChartRoom; //主线程对话框指针
此时编译会报错: ‘inet_ntoa’: Use inet_ntop() or InetNtop() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings chartroom d:\vs2017项目\打造局域网聊天室\chartroom\chartroom\server.cpp 100
这是由于函数inet_ntoa过旧,此时需要在项目的属性中把SDL检查设置为否。

二、相关函数
后续的客户端队列的建立过程需要依赖一些函数,我们先实现这些函数,再回来继续客户端队列的建立过程。
聊天信息显示函数:
由于服务端每次都需要显示全部的聊天记录,而不是只显示当前的聊天记录,这就需要我们对之前的聊天内容进行保存。
首先对显示聊天内容的编辑框绑定一个成员变量。

设置一个变量名称,其他都为默认值

此时在chartroomDlg.h头文件内会自动声明该变量。

并且在chartroomDlg.h头文件中声明一个函数,用于声明聊天信息显示函数

在chartroomDlg.cpp源文件中实现函数ShowMsg()
// 实现聊天信息显示函数
void CchartroomDlg::ShowMsg(CString strMsg)
{m_MsgEdit.SetSel(-1, -1); // 将光标定位到文字的最后一个位置m_MsgEdit.ReplaceSel(strMsg + _T("\r\n")); // 将光标替换为strMsg + _T("\r\n")
}
从队列中删除客户端函数:
如果客户端关闭,此时服务端对应的客户端结点还在客户端队列中,那么就需要将客户端结点从客户端队列中删除。
同样先在chartroomDlg.h头文件内声明函数,使得类CchartroomDlg中包含成员函数

在chartroomDlg.cpp源文件中实现函数RemoveClientFromArray()
// 实现从队列删除客户端结点函数
void CchartroomDlg::RemoveClientFromArray(CClientitem in_Item) //参数为需要删除的客户端结点
{for (int idx = 0; idx < m_ClientArray.GetCount(); idx++) // 遍历客户端队列中的每一个结点{CClientitem tItem = m_ClientArray.GetAt(idx);if (tItem.m_Socket == in_Item.m_Socket && tItem.hThread == in_Item.hThread && tItem.m_surlp == in_Item.m_surlp) //队列中的该结点为需要删除的结点{m_ClientArray.RemoveAt(idx); // 删除结点}}
}
现在我们回到Server.cpp文件中,继续客户端队列的建立过程。
接下来初始化该客户端结点的线程句柄,同服务端创建线程,利用函数 CreateThread()。
// 客户端队列的添加CClientitem tItem; //定义一个客户端结点tItem.m_Socket = accSock; //客户端的socket即为accept函数返回的accSocktItem.m_surlp = inet_ntoa(clientAddr.sin_addr); // 客户端的IP包含在clientAddr结构中。inet_ntoa()函数将网络字节顺序的Ip转化为本机格式的字符串(192.192.1.1)tItem.m_pMainWnd = pChartRoom; //主线程对话框指针// 每一个客户端对应线程的句柄。说明:一个服务端对应多个客户端,在while死循环中调用accept接受一个客户端的连接之后,还可以在其他循环时接受// 其他客户端连接,每有一个客户端连接,我们创建一个客户端结点,将客户端结点的信息加入到客户端队列当中。//!!!!!!!!注意:该线程只进行监听端口,等待连接客户端的操作,接受连接客户端传来的消息等功能还需要新开一个线程进行处理,新开的线程与连接的客户端进行通信INT_PTR idx = pChartRoom->m_ClientArray.Add(tItem); // 将客户端结点放入队列中tItem.hThread = CreateThread(NULL, 0, ClientThreadProc, &(pChartRoom->m_ClientArray.GetAt(idx)), CREATE_SUSPENDED, NULL);// 初始化该客户端结点的线程句柄,注意第四个参数不要传递tItem的地址,CREATE_SUSPENDED表示该线程不要立即执行//这是因为如果有多个客户端来连接,tItem会一直变为最新连接的客户端结点,但是之前调用的以前连接的客户端结点也是用tItem,此时tItem已经存储的没有//之前连接的客户端结点的内容了pChartRoom->m_ClientArray.GetAt(idx).hThread = tItem.hThread; //将tItem的线程句柄同时赋给客户端队列中对应的客户端的线程句柄// 至此,该客户端的结点信息填充完毕ResumeThread(tItem.hThread); //与CREATE_SUSPENDED对应,在这里才开始执行被CREATE_SUSPENDED修饰的线程
下面介绍该线程的程序ClientThreadProc()函数的具体实现
// 实现客户端的创建线程函数,与接受的客户端进行通信的线程函数
DWORD WINAPI ClientThreadProc(LPVOID IpParameter) // 传入的参数为&(pChartRoom->m_ClientArray.GetAt(idx))
{CString strMsg;CClientitem m_ClientItem = *(CClientitem*)IpParameter; // 将传入的地址利用强制类型转换为客户端结点类型,不使用地址是怕误修改while (TRUE) // 用于监听该连接的客户端是否发送消息{if (SOCKET_Select(m_ClientItem.m_Socket, 100, TRUE)) //向缓冲区“偷看”一眼是否有客户端发过来的消息{TCHAR szBuf[MAX_BUF_SIZE] = { 0 }; // 申请缓冲区// recv函数:第一个参数为接收哪一个socket的数据;第二个参数为窄字节的缓冲区,存放接收过来的数据,要申请一块内存//第三个参数:缓冲区的长度;第四个参数平时为0即可。正常返回接收字节个数int iRet = recv(m_ClientItem.m_Socket, (char*)szBuf, MAX_BUF_SIZE,0); // 调用recv函数接受缓冲区中客户端发过来的消息if (iRet > 0){//正确,接收数据成功strMsg = szBuf; //为了操作方便(使用模板类函数),这里我们使用CString类型strMsg = _T("客户端:") + m_ClientItem.m_surlp + _T(">") + strMsg;m_ClientItem.m_pMainWnd->ShowMsg(strMsg); //利用在chartroom.cpp中实现的ShowMsg方法将信息显示}else // 接收数据失败,有错误或者客户端关闭了{// 关闭socketstrMsg = _T("客户端") + m_ClientItem.m_surlp + _T("离开了聊天室!");m_ClientItem.m_pMainWnd->ShowMsg(strMsg); //利用在chartroom.cpp中实现的ShowMsg方法将信息显示m_ClientItem.m_pMainWnd->RemoveClientFromArray(m_ClientItem); // 利用在chartroom.cpp中实现的RemoveClientFromArray方法在客户端队列中删去该客户端结点break;// 跳出循环,客户端已下线,退出线程}}Sleep(500);}return TRUE;
}
总结
C++打造局域网聊天室第九课: 客户端队列及其处理线程
相关文章:
C++打造局域网聊天室第九课: 客户端队列及其处理线程
文章目录 前言一、添加客户端队列的参数初始化二、相关函数总结 前言 C打造局域网聊天室第九课: 客户端队列及其处理线程 一、添加客户端队列的参数初始化 在Server.cpp的 ListenThreadFunc()函数内的其他操作处实现客户端队列的添加。 首先进行部分参数的初始化…...
请求go web后端接口 java安卓端播放视频
前端代码 添加gradle依赖 implementation com.squareup.retrofit2:retrofit:2.9.0 implementation com.squareup.retrofit2:converter-gson:2.9.0 添加访问网络权限 <uses-permission android:name"android.permission.INTERNET" />允许http 请求请求 andro…...
XML Schema 复合类型 - 混合内容
XML Schema 复合类型 - 混合内容 XML Schema 是一种用于定义 XML 文档结构和内容的语言。在 XML Schema 中,复合类型是一种包含其他元素和/或属性的复杂类型。混合内容(Mixed Content)是复合类型的一种特殊形式,它允许元素包含其…...
第8章 搬移特性
8.1 搬移函数 模块化是优秀软件设计的核心所在,好的模块化能够让我在修改程序时只需理解程序的一小部分。为了设计出高度模块化的程序,我得保证互相关联的软件要素都能集中到一块,并确保块与块之间的联系易于查找、直观易懂。同时,…...
ARM/Linux嵌入式面经(五九):海尔
1.以后打算在哪里工作 问题回答: 1. 以后打算在哪里工作? 回答这个问题时,我首先会考虑我的个人目标、职业规划以及家庭和生活因素。从职业发展的角度来看,我希望能够在技术氛围浓厚、创新能力强、且能提供良好职业成长机会的地方工作。具体来说,我对以下几个方向特别感…...
java中的List、数组和set
在Java中,List、数组(Array)和Set 是三种常用的数据结构,它们各自有不同的特性、用途和实现方式。下面我们将深入探讨这三者的特点、区别以及它们在 Java 中的常见使用场景。 1. 数组(Array) 特性&#x…...
freeswitch(配置文件结构)
vars.xml<X-PRE-PROCESS cmd="set" data="default_password=1234"/>default_password:设置默认密码,为安全起见,建议在部署后立即更改此密码,以防止盗用。<X-PRE-PROCESS cmd=<...
ARMS 用户体验监控正式发布原生鸿蒙应用 SDK
作者:羿莉 背景 对企业数据进行敏感数据扫描和保护可以提升企业或组织的数据安全。一方面敏感数据可能包括个人身份信息、财务记录、医疗记录等,定期扫描这些数据可以防止未经授权的访问和泄露。 另一方面,许多国家和地区都有关于数据保护的…...
使用 esrally race 测试 Elasticsearch 性能:实践指南
在 Elasticsearch 性能优化和容量规划中,使用 esrally 进行基准测试是官方推荐的方式。通过 esrally race 命令,您可以针对不同的数据集与挑战类型,对 Elasticsearch 集群进行精确的性能评估。本文将简要介绍常用的数据集与挑战类型ÿ…...
OkHttp源码分析:分发器任务调配,拦截器责任链设计,连接池socket复用
目录 一,分发器和拦截器 二,分发器处理异步请求 1.分发器处理入口 2.分发器工作流程 3.分发器中的线程池设计 三,分发器处理同步请求 四,拦截器处理请求 1.责任链设计模式 2.拦截器工作原理 3.OkHttp五大拦截器 一&#…...
中国计算机学会计算机视觉专委会携手合合信息举办企业交流活动,为AI安全治理打开“新思路”
近期,《咬文嚼字》杂志发布了2024年度十大流行语,“智能向善”位列其中,过去一年时间里,深度伪造、AI诈骗等话题屡次登上热搜,AI技术“野蛮生长”引发公众担忧。今年9月,全国网络安全标准化技术委员会发布了…...
重生之我在异世界学编程之C语言:深入预处理篇(上)
大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文一、预处理的作用与流程…...
dolphinscheduler服务RPC框架源码解析(二)RPC核心注解@RpcService和@RpcMethod设计实现
1.工程目录 从3.2.1版本之后这个dolphinscheduler中的RPC框架工程就从原来的dolphinscheduler-remote工程重构到了dolphinscheduler-extract工程。 dolphinscheduler 父项目 dolphinscheduler-extract RPC服务项目 dolphinscheduler-extract-alert 监控告警服务RPC接口定义、…...
【从零开始入门unity游戏开发之——C#篇04】栈(Stack)和堆(Heap),值类型和引用类型,以及特殊的引用类型string
文章目录 知识回顾一、栈(Stack)和堆(Heap)1、什么是栈和堆2、为什么要分栈和堆3、栈和堆的区别栈堆 4、总结 二、值类型和引用类型1、那么值类型和引用类型到底有什么区别呢?值类型引用类型 2、总结 三、特殊的引用类…...
ARCGIS国土超级工具集1.2更新说明
ARCGIS国土超级工具集V1.2版本,功能已增加至47 个。在V1.1的基础上修复了若干使用时发现的BUG,新增了"矢量分割工具"菜单,同时增加及更新了了若干功能,新工具使用说明如下: 一、勘测定界工具栏更新界址点成果…...
暂停window11自动更新
window11 的自动更新功能,一方面在后台占用资源,容易导致电脑卡顿;另一方面,“更新并关机” 和 “更新并重启” 的设置令人极其反感。很多补丁兼容性很差,更新后极易引发电脑蓝屏、闪屏等意想不到的 bug。 1.winR打开运…...
Git简介和特点
目录 一、Git简介 二、Git特点 1.集中式和分布式 (1)集中式版本控制系统 (2)分布式版本控制系统 2.版本存储方式的差异 (1)直接记录快照,而非差异比较 3.近乎所有操作都是本地执行 一、Git简介 Git是目前世界上最先进的的分布式控制系统(没有之一…...
如何通过docker 部署minio,端口号为9105
通过Docker部署MinIO对象存储服务,并指定API端口为9105,可以按照以下步骤进行。我们将基于已有的资料来详细说明这一过程。 1. 准备工作 首先,确保你的系统上已经安装了Docker。如果没有安装,可以根据官方文档指导完成安装。接下…...
设置Qt程序开机自启动(windows版本)
前言 本文展示在windows环境下,通过代码实现更改系统注册表的方式来实现程序的开机自动启动。 一、注册表 需要更改的系统注册表为: HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run 二、代码演示 1.头文件 头文件autorun.h #ifndef …...
【HarmonyOS】鸿蒙获取appIdentifier,Identifier
【HarmonyOS】鸿蒙获取appIdentifier,Identifier 一、前言 三方后台需要填写的所谓appIdentifier,Identifier信息,其实对应鸿蒙应用的appID。 二、解决方案: 注意,模拟器获取data.signatureInfo.appIndentifer为空…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
