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为空…...

【Rust自学】3.5. 控制流:if else
3.5.0. 写在正文之前 欢迎来到Rust自学的第三章,一共有6个小节,分别是: 变量与可变性数据类型:标量类型数据类型:复合类型函数和注释控制流:if else(本文)控制流:循环 通过第二章…...

美国信息学奥林匹克竞赛USACO 2024年12月比赛铜级问题1. 循环舍入-答案代码
题目见: USACO 2024年12月比赛铜级问题1. 循环舍入(USACO 2024 December Contest, Bronze Problem 1. Roundabount Rounding) 最简单的青铜级 亲测所有得分点通过哈! 下一篇会给解题分析哦! #include <iostream> using namespace std;…...

Llama3模型详解 - Meta最新开源大模型全面解析
📚 Meta最新发布的Llama3模型在开源社区引起广泛关注。本文将全面解析Llama3的技术特点、部署要求和应用场景。 一、模型概述 1. 基本信息 发布机构: Meta AI开源协议: Llama 2 Community License Agreement模型规格: 7B/13B/34B/70B训练数据: 2万亿tokens上下文长…...

2021-02-12 c++里面cin.sync()函数的意思
回复急~救救菜鸡吧,C用cin.clear()和cin.sycn()清空缓存区一直清不了!_编程语言-CSDN问答 标识符号为:goodbit 无错误 Eofbit 已到达文件尾 failbit 非致命的输入/输出错误可挽回 badbit 致命的输入/输出错误无法挽回 int a 0;cin >> a;if (cin.rdstate() i…...

下载红米Note 9 Pro5G对应的LineageOS代码下载及编译
构建 LineageOS 进入网站:Info about gauguin | LineageOS Wiki,点击:Build for yourself,里面有详细的教程,我这里就按照Note 9 Pro 5G来。 机器环境 Ubuntu环境为:20.04.6LinagesOS版本:21-…...

《探索 Caffe2 的 C++接口在移动设备上的性能优化之路》
在当今移动应用日益智能化的时代,将深度学习框架如 Caffe2 的 C接口应用于移动设备上已成为众多开发者的目标。然而,移动设备资源相对有限,如何优化其性能成为了关键挑战。 一、移动设备应用深度学习的现状与挑战 随着智能手机等移动设备的…...

1.编写一个程序,给定一个大写字母,要求用小写输出
思路:ascII码值 例如:A的ASCII码值为65,a的ASCII码值为97,不难发现,大小写字母之间的ascii值相差了32 #include <stdio.h> int main() {char c;scanf("%c",&c);printf("%c",c32);retu…...

条件随机场(CRF)详解:原理、算法与实现(深入浅出)
目录 1. 引言2. 什么是条件随机场?2.1 直观理解2.2 形式化定义 3. CRF的核心要素3.1 特征函数3.2 参数学习 4. 实战案例:命名实体识别5. CRF vs HMM6. CRF的优化与改进6.1 特征选择6.2 正则化 7. 总结与展望参考资料 1. 引言 条件随机场(Conditional Ra…...

Android Studio、JDK、AGP、Gradle、kotlin-gradle-plugin 兼容性问题
文章目录 问题:解决办法:gradle与 java的版本兼容AGP与Gradle的版本兼容kotlin 与 jvm 的版本兼容KGP、Gradle、AGP兼容关系kotlin 与 java 的编译版本配置 问题: 你从githb上clone了一个项目,本地跑的时候,各种报错。…...

防抖(Debounce)和节流(Throttle)的区别和应用场景
防抖(Debounce)和节流(Throttle)虽然都是用来限制函数的执行频率,但它们的实现方式和应用场景有所不同。以下是两者的主要区别: 1. 执行原理 防抖(Debounce): 执行条件&a…...