当前位置: 首页 > news >正文

网络服务退出一个问题的解析

一、问题

在实际开发中遇到一个问题,解决的过程虽然不长,但确实是想得比较多,总结一下,以供参考。这是一个网络通信的服务端而且使用的是别人封装好的库,通信等都没有问题,但在退出时会报一个错误:“Failed to accept the socket”。这个错误引起的原因,通过查看堆栈信息和库源码,发现是服务端在线程中Wait时唤醒后会调用Accept函数引起的。虽然在退出时延时1秒可以解决问题,但这不是优雅的方式。一开始是认为封装库的Wait等待1秒造成必须退出时也跟着等待1秒。但在后来发现,线程的处理中其实已经有对退出线程的等待。以前遇到过类似问题,没有重视,这次一起搞定。

二、解决

解决的方法用了不少,下面一个个分析:
1、把原来的全局网络封装库变量修改为局部指针后,问题消失,即类似如下:

netlib nl;//全局变量
int net(){
...//netlib nl;//局部变量netlib * nl = new netlib;
std::thread td = std::thread([&](){nl.init();nl.stop();//修改为nl->init();nl.stop();});//td.deatch();//delete nl;//主动删除...td.join();
}

通过打印的日志发现,指针不主动回收由操作系统在程序完成后回收时,是不调用析构函数的。如果将上面的注释的删除指针解开,则会调用析构函数。但是对于局部和全局变量来说,则会主动调用析构函数,而错误也就是在这个析构函数中产生的。
2、释放顺序和析构函数
在netlib内部的接收网络数据函数中,也有一个线程,为了线程的安全退出在析构函数调用了类似下而把 机制:

netlib::~netlib{closesocket();//注意这个函数是调用的父类的函数,问题就在这if (td && td->joinable()) {td->join();}
// closesocket();//正确
}

理论上讲不会出现这个问题,但实际上只要是使用变量而不是指针(不主动删除)或者主动删除指针,同样会出现文中的异常。因为封装的库是继承了Socket类,所有的操作几乎全在父类中进行,于是突然怀疑是不是父类被先释放了相关值造成的,然后试着打印了一下(注意,这里引入了假的二次释放问题),验证确实如此。可忽然想到,释放顺序中,父类是后被释放的,这不符合道理的(不考虑虚基类)。于是写了一个相关释放的过程,发现确实是如此。
3、二次析构
事情到此,基本已经明了,然后 开始出昏招。由于程序都在一个工程中修改的,结果开始出现重复释放崩溃的问题,也就是说,有两次调用析构函数的动作,那想当然啊,二次析构崩溃的概率太大了。这个问题定位了足有半小时,才突然想起来是不是全局变量导致的,可又一想全局变量调用也不应该崩溃啊,毕竟全局变量只是定义了一下,又没有工作,连初始化都没有。然后自然就想起了为了验证父类先释放引入的函数,果然。这里说一下,这个netlib类有一个变量,它可以在判断返回是否为空指针,它有点稍微误导人,让人认为其可以使用,特别是在此次调试过程中,乱了套了。于是把后面的非判断空的函数上移,果然直接崩溃。立刻明白了怎么回事,引入了新BUG,二次释放崩溃不是真正的二次释放,是两个变量当然释放两次,只是因为引用了空指针调用相关函数,不崩溃会怎么样?

4、解决问题
这时候重新回来审视析构函数,经过分析日志,发现了端倪,那个异常总是在进入析构函数后,进入到第一个判断join后出现,而这个join意味着线程还活着,还在操作Socket,可一进入析构函数就调用了那个closesocket函数,它不能在前面啊,使用了它,当然后面的判断中父类中的指针当然是空的,线程在Wait(调用Accept)当然会报一个异常。然后 把其后移到正确位置,一切OK。
大意了,资源的释放一定要有顺序,在使用者之后再释放,或者提前使用函数控制线程退出(这也是测试的过程中使用的,即要stop函数中进行了线程的集中退出),只在析构函数中处理资源。其实这才是正规的处理方式,不要在构造和析构函数里进行业务相关的代码控制,此次使用封装库,降低了戒备心,致此结果。

三、扩展

在上面解决问题的基础上,又想到两个问题:
1、使用智能指针
使用智能指针测试的结果和变量基本类似(但得去除主动删除指针的代码),会有一个析构的动作,其它都没有问题。代码类似于:

  auto nl = netlib::get();std::thread td = std::thread([&]() {nl->init();nl->stop();});

2、使用线程detach
在前面的线程中使用了线程join的方式,让各个线程协调有序的退出,其实也可以使用detach,让线程主动分离。在本次的工程中,这样做是没有问题的,但需要注意的是,如果需要协调各个线程中有相关资源时互相调用时,还是需要处理一下线程中退出的顺序,否则仍然会引起崩溃。
这里只是一个Socket的接收动作,从打印日志看,直接就退出了子线程,然后 父线程再调用析构函数(调用关闭Socket)退出。
这个问题,连带测试用例和相关分析,用了小半天时间,也是一个教训吧。

四、总结

其实,正如前面的分析,解决问题的思路其实就是基础知识的检查过程。在这次解决问题的过程中,数次发现和基础知识理解对不上,所以否定了自己的想法(比如析构函数的顺序)。只要按照标准和规则来,解决问题一定是水到渠成的。不要总想着弯道超车,没有大量的基础知识做底子,超车也是运气的结果。
这次解决这个问题,正是一次比较多面的对基础知识的一次综合运用,收获颇丰。

相关文章:

网络服务退出一个问题的解析

一、问题 在实际开发中遇到一个问题,解决的过程虽然不长,但确实是想得比较多,总结一下,以供参考。这是一个网络通信的服务端而且使用的是别人封装好的库,通信等都没有问题,但在退出时会报一个错误&#xf…...

第四次pta认证P测试

第一题 试题编号: 试题名称:整数排序 时间限制: 1.0s 内存限制: 128.0MB 【问题描述】 老师给定 10 个整数的序列,要求对其重新排序。排序要求: 1.奇数在前,偶数在后; 2.奇数按从大到小排序&am…...

mysql:B+树/事务

B树 : 为了数据库量身定做的数据结构 我们当前这里的讨论都是围绕 mysql 的 innodb 这个存储引擎来讨论的 其他存储引擎可能会用到hash 作为索引,此时就只能应对这种精准匹配的情况了 要了解 B树 我们先了解 B树, B树 是 B树 的改进 B树 有时候会写作 B-树 (这里的" -…...

python-在系统托盘显示CPU使用率和内存使用率

一、添加轮子 1.添加托盘区图标库 infi.systray from infi.systray import SysTrayIcon 2.添加图像处理库 Pillow from PIL import Image, ImageDraw, ImageFont 3.添加 psutil 来获取CPU、内存信息 import psutil 二、完整代码 from infi.systray import SysTrayIcon …...

构建mono-repo风格的脚手架库

前段时间阅读了 https://juejin.cn/post/7260144602471776311#heading-25 这篇文章;本文做一个梳理和笔记; 主要聚焦的知识点如下: 如何搭建脚手架工程如何开发调试如何处理命令行参数如何实现用户交互如何拷贝文件夹或文件如何动态生成文件…...

云安全—etcd攻击面

0x00 前言 本篇还是一样,先来说一说etcd是什么,干啥的,然后再来看看etcd的攻击面到底有哪些,做一个抛砖引玉的作用,如有不妥之处还请斧正 0x01 etcd 依旧还是按照问问题的方式来进行阐述,因为学到的东西…...

类锁和实例对象锁你分清了吗?

系列文章目录 文章目录 系列文章目录前言一、什么是锁竞争?二、什么是类锁?什么是实例对象锁?三、给类对象加锁不是锁住了整个类四、总结 前言 java选手们应该都对锁不陌生,加锁了就是为保证操作语句的原子性,如果你是…...

如何在麒麟上安装 ONLYOFFICE 桌面编辑器

我们很高兴地告诉大家,ONLYOFFICE 桌面编辑器现已上架麒麟软件商店。请阅读下文了解详情。 关于麒麟 麒麟是一款国产操作系统,主要是为了满足中国市场的需求和偏好而设计的。 它能够与各种硬件平台和软件应用程序的广泛兼容,因而受到认可。…...

记录:如何编写linux驱动,用module的方式

记录:如何编写Linux驱动,用module的方式 记录:如何编写Linux驱动,用module的方式参考记录:如何编写Linux驱动,用module的方式 编写一个 Linux 的驱动,用 module 方式开发,一般来说,编写一个 Linux 的驱动,需要遵循以下步骤: 确定设备的类型和功能,以及它在系统中的…...

3款免费又好用的 Docker 可视化管理工具

前言 Docker提供了命令行工具(Docker CLI)来管理Docker容器、镜像、网络和数据卷等Docker组件。我们也可以使用可视化管理工具来更方便地查看和管理Docker容器、镜像、网络和数据卷等Docker组件。今天我们来介绍3款免费且好用的 Docker 可视化管理工具。…...

C语言--判断一个年份是否是闰年(详解)

一.闰年的定义 闰年是指在公历(格里高利历)中,年份可以被4整除但不能被100整除的年份,或者可以被400整除的年份。简单来说,闰年是一个比平年多出一天的年份,即2月有29天。闰年的目的是校准公历与地球公转周…...

Python---排序算法

文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 前言 Python中的排序算法用于对数据进行排序。排序算法可以使数据按照一定的规则进行排列,以便于数据的查找、统计、比较等操作。在数据分析、机器学习、图形计算等领域&#xff0c…...

gitlab Blocking and unblocking users

原文:Redirecting... Blocking a userUnblocking a user Blocking and unblocking users GitLab 管理员阻止和取消阻止用户. Blocking a user 为了完全阻止用户访问 GitLab 实例,管理员可以选择阻止该用户. 可以通过滥用报告或直接从管理区域来阻止…...

Swift 和 Python 两种语言中带关联信息错误(异常)类型的比较

0. 概览 如果我们分别在平静如水、和谐感人的 Swift 和 Python 社区抛出诸如“Python 是天下最好的语言…” 和 “Swift 是宇宙第一语言…”之类的言论会有怎样的“下场”? 我们并不想对可能发生的“炸裂”景象做出什么预测,也无意比较 Swift 与 Pytho…...

北京联通iptv组播配置

多年前折腾过iptv,近期搬家换了个大电视,打算把iptv配置好了,尽管不怎么看,但聊胜于无。 其实很简单,用到了一些工具,记录如下 1. openwrt配置 因为有软路由,所以就借助openwrt了,一…...

C++ STL 迭代器失效

一、学习资料 STL迭代器的使用 二、vector容器获取值是下标法和at()的区别 vector<int> vA; int array[]{0,1,2,3,4}; vA.assign(array,array5); cout<<vA[6]<<endl; cout<<va.at(6)<<endl;如上述代码&#xff0c;当使用vA[6]的方式出现访问越…...

麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包

原文链接&#xff1a;麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包 hello&#xff0c;大家好啊&#xff0c;今天给大家带来麒麟桌面操作系统软件仓库搭建的文章02-软件仓库添加新的软件包&#xff0c;本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上&…...

专业媒体播放软件Movist Pro中文

Movist Pro是一款专为Mac用户设计的专业媒体播放器。它支持广泛的视频和音频格式&#xff0c;包括MP4、AVI、MKV等&#xff0c;并提供了高级播放控件和定制的视频设置。其直观易用的用户界面&#xff0c;使得播放高清视频更为流畅&#xff0c;且不会卡顿或滞后。同时&#xff0…...

数据结构-邻接表广度优先搜索(C语言版)

对于一个有向图无向图&#xff0c;我们下面介绍第二种遍历方式。 广度优先搜索&#xff0c;即优先对同一层的顶点进行遍历。 如下图所示&#xff1a; 该例子&#xff0c;我们有六个顶点&#xff0c; 十条边。 对于广度优先搜索&#xff0c;我们先搜索a&#xff0c;再搜索abc…...

Py之auto-gptq:auto-gptq的简介、安装、使用方法之详细攻略

Py之auto-gptq&#xff1a;auto-gptq的简介、安装、使用方法之详细攻略 目录 auto-gptq的简介 1、版本更新历史 2、性能对比 推理速度 困惑度&#xff08;PPL&#xff09; 3、支持的模型 3、支持的评估任务 auto-gptq的安装 auto-gptq的使用方法 1、基础用法 (1)、量…...

网络协议深度解析:从OSI七层模型到TCP/IP实战应用

1. OSI七层模型&#xff1a;网络世界的通用语言 第一次接触OSI七层模型时&#xff0c;我完全被那些专业术语搞晕了。直到后来在实际项目中调试网络问题&#xff0c;才真正理解这个模型的精妙之处。简单来说&#xff0c;OSI模型就像是一本网络通信的"使用说明书"&…...

SwiftHub:终极GitHub iOS客户端开发指南 - RxSwift与MVVM-C架构实践

SwiftHub&#xff1a;终极GitHub iOS客户端开发指南 - RxSwift与MVVM-C架构实践 【免费下载链接】SwiftHub GitHub iOS client in RxSwift and MVVM-C clean architecture 项目地址: https://gitcode.com/gh_mirrors/sw/SwiftHub SwiftHub是一款功能强大的GitHub iOS客户…...

VisualVM安全监控指南:敏感数据保护与权限管理

VisualVM安全监控指南&#xff1a;敏感数据保护与权限管理 【免费下载链接】visualvm VisualVM is an All-in-One Java Troubleshooting Tool 项目地址: https://gitcode.com/gh_mirrors/vi/visualvm VisualVM作为一款强大的Java应用性能监控与故障诊断工具&#xff0c;…...

Git GUI里那些小箭头和蓝点到底是啥?一份给新手的保姆级图解指南

Git GUI可视化指南&#xff1a;解码提交历史中的符号与分支拓扑 第一次打开Git GUI的提交历史视图时&#xff0c;那些彩色线条、小蓝点和神秘箭头就像天书般令人困惑。作为从SVN过渡到Git的开发者&#xff0c;我曾盯着这些符号发呆半小时——直到发现它们其实是项目历史的可视化…...

SDXL 1.0电影级绘图工坊真实案例:文化遗产数字化重建与风格复原实践

SDXL 1.0电影级绘图工坊真实案例&#xff1a;文化遗产数字化重建与风格复原实践 想象一下&#xff0c;你面前有一张因年代久远而模糊不清的古建筑照片&#xff0c;或是仅存于文字描述中的历史场景。如何将它们清晰地、生动地、甚至以不同艺术风格再现出来&#xff1f;这曾是考…...

实战指南 | TSMaster 的 CAN UDS 诊断自动化流程与 BootLoader 刷写详解

1. TSMaster诊断控制台深度解析 诊断控制台是TSMaster进行UDS诊断的核心操作界面&#xff0c;相当于工程师与ECU对话的"翻译器"。我第一次接触这个界面时&#xff0c;被它清晰的四分区设计惊艳到了——就像汽车仪表盘把转速、车速、油量分区域显示一样直观。 服务命令…...

Win10 22H2多合一版本实测:家庭版/专业版/企业版到底有什么区别?

Win10 22H2多合一版本深度解析&#xff1a;如何根据需求选择最佳系统版本 当你面对一个包含家庭版、专业版、企业版等多个版本的Win10 22H2多合一ISO镜像时&#xff0c;是否曾感到困惑&#xff1a;这些版本之间究竟有什么区别&#xff1f;哪个版本最适合我的使用场景&#xff1…...

告别手动复制粘贴:MeterSphere参数提取功能详解,让你的接口自动化测试效率翻倍

MeterSphere参数提取实战&#xff1a;构建动态接口测试链的三大高阶技巧 在持续集成环境中&#xff0c;接口自动化测试往往面临一个关键挑战&#xff1a;如何让不同接口之间实现数据动态传递&#xff1f;传统的手动复制粘贴不仅效率低下&#xff0c;更难以应对复杂业务场景。Me…...

Cat-Catch实战手册:5个场景快速掌握网页资源抓取技巧

Cat-Catch实战手册&#xff1a;5个场景快速掌握网页资源抓取技巧 【免费下载链接】cat-catch 猫抓 chrome资源嗅探扩展 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否经常遇到这样的困境&#xff1f;在线课程视频无法下载、设计素材图片无法批量保…...

开源DapFlash深度体验:除了下载程序,它的HEX编辑器还能帮你做什么?

开源DapFlash深度体验&#xff1a;HEX编辑器的隐藏技能树 当大多数嵌入式工程师将DapFlash视为又一个程序烧录工具时&#xff0c;它的HEX编辑器正在芯片深处执行着堪比"数字考古"的任务。上周在调试一款智能家居主控板时&#xff0c;我意外发现Bootloader区域被异常覆…...