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为空…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...