Skip to content

一些开发过程中遇到的奇怪问题

ssl socket读数据总是会卡住

需求是要给一个开源库中的socket通信加入ssl/tls层,这个第三方库实现了一套nfs协议,用于局域网文件共享

ssl/tls层是用openssl库实现的,测试过程中遇到了一个问题,在传输大文件的时候(几十MB以上),传输过程总是会卡住,百思不得其解

仔细分析日志后发现传输过程卡在了ssl socket提供的peek函数上,查看openssl文档后发现,openssl的ssl socket不是流式传输,是以包为单位的传输,一个包最大16KB,openssl内部的read buffer中的数据量一旦达到了16KB,如果不把这些数据读走是peek不到更多数据的

后来对peek操作做了一个二次封装,在代码中维护了一个临时的buffer,把peek到的数据先读到buffer里,这样就不会导致程序卡在peek上了

问题分析过程非常坎坷,首先很难打断点调试,因为需要同时调试两个进程,而且两个进程之间存在网络通信,为了测试真实的网络通信环境,这两个进程分别跑在两台不同的pc上,如果在一个进程里打断点,另外一个进程很可能出错或者崩溃,所以只能通过打日志分析,然而原本的日志库是同步的,及其影响性能,我花了很多时间先把日志库改成异步输出日志,这才顺利地完成了问题定位

编译环境从win10 sdk降级到win 8sdk后,进程一启动就卡死

项目最开始的开发环境是win10 sdk,vs2022(v143)工具集,程序工作一切正常,后来要将项目作为插件集成到另外一个平台,为了兼容将项目的开发环境降级到win8 sdk,vs2015(v140)工具集,降级后发现进程一启动就卡死

在调试模式下运行发现,总是卡在创建一个线程的地方,这个创建线程的位置比较特殊,是写在了一个dll的全局对象的构造函数里,这意味着dll被加载的时候会触发线程创建的操作

经过查阅资料得知,在windows sdk的早期版本中,是不允许在dll加载的时候创建线程的,会造成dll加载死锁,然后我们把创建线程改为由上层调用函数触发,解决了问题

进程被多次拉起

主进程会通过shell拉起多个另外一个进程(之所以要用shell拉起,是为了使被拉起的进程以管理员权限启动),然而在某些特殊的情况下,拉起进程时会有一个额外的进程启动,启动参数还不符合预期,我作为进程管理模块的开发者,很清楚这个额外的进程一定不是由进程管理模块拉起的,一定是有什么第三方的进程在拉起这个进程

又是坎坷的找证据过程,首先,进程拉起的数量和日志中的日志中的拉起进程次数并不对应,并且日志中的进程启动参数都是正确的,然而其他同事并不相信日志,于是我是用sysinternal套件中的procmon工具查看进程树,发现额外拉起的进程并不是由任何一个已知进程拉起的,而日志中对应的那个正常拉起的进程,在进程树上存在一个已知的父进程,这时同事们还是不相信进程是由第三方拉起的,于是我使用windows的ifeo机制将进程管理模块劫持到windbg,直接对进程进行内核调试,对windows的CreateProcess api打断点,发现问题复现时,只能命中一次断点,至此结果已经很清楚了,虽然我们还是不清楚额外的进程是由谁拉起来的,但是显然不是由我的进程管理模块拉起的

使用ffmpeg的GPU编解码器处理视频时卡死

原因是出错时ffmpeg不会退出,而是不停地输出error信息,而我们的程序逻辑是先等ffmpeg退出,再去检索ffmpeg的错误信息中是否有error,将程序逻辑修改为在ffmpeg运行时实时检测error信息,而不是等ffmpeg退出时再去检查error

ffmpeg进程卡死,第一反应是直接在命令行执行一下这句ffmpeg命令,通过这种方法排查到了问题

至于为什么ffmpeg会出现这种情况,原因是nvdia的gpu解码器h264_cuvid不支持yuv444p像素格式,参考https://forums.developer.nvidia.com/t/yuv444p-video-decoding-with-ffmpeg-error-cuda-error-not-supported-operation-not-supported/213308

使用ffmpeg叠加两个视频时,无法正确识别前景视频的透明通道

原因是前景视频的编码方式是vp9编码(webm封装格式),而ffmpeg无法自动检测出视频的vp9编码,需要手动指定libvpx-vp9解码器

查stackoverflow查到的

读取到的文件名总是乱码

原因是文件名中包含中文字符,而系统locale设置的是美国,保存文件名使用的是char类型字符串,char类型字符串默认使用的是ANSI编码,而美国对应的ANSI编码字符集是不支持中文的,所以char类型字符串总是乱码。

解决方法是使用宽字符版本的api获取文件名,宽字符版本的api使用的是utf-16编码,无论locale是什么,都可以正确识别中文

子进程启动不了,子进程也没打出任何日志,没有dump

是因为缺少几个被子进程依赖的dll,导致子进程启动失败

是通过获取在父进程里获取子进程的退出码定位到的,这也给我们提供了一个思路,后续如果再遇到类似问题,可以往这个方向定位问题