最近两天在调试一个关于嵌入式Linux系统环境时,在系统开机之后,Mosquitto通过tls连接MQTT服务器(EMQ)时,创建MQTT连接总是阻塞的问题,现记录一下调试过程及解决问题的步骤。

先说下开发调试环境:

  • 硬件平台:EXP imx.6ull
  • 内核版本:4.1.15
  • rootfs:基于buildroot创建
  • mosquitto:2.0.11
  • openssl:1.1.1
  • MQTT服务器:支持TLS服务的EMQ

问题表象

linux系统开机之后,出现shell登录提示符之后,调用mosquitto_connect和EMQ建立基于TLS的连接,mosquitto_connect调用之后阻塞,大约90秒,该函数调用才会返回,并且报错。之后,mosquitto会触发重连机制,再次连接EMQ服务器,连接成功。这时,如果重新发起向EMQ的连接请求,mosquitto_connect不会阻塞。

起初怀疑的几点原因:

  1. 系统启动之后,网络还未初始化完成,就调用了mosquitto_connect,连接EMQ可能失败。尝试测试方法:完善网络初始化流程,优化mosquitto_connect调用时序,经测试,无效。
  2. 怀疑EMQ服务器问题,尝试测试方法:使用其他设备测试对同一EMQ发起TLS连接,没有问题。
  3. 开机时,系统时间未同步(1970-01-01 08:00:00),联网之后,ntpd服务才会同步网络时间到本地,所以中间会导致mqtt连接阻塞,经过思考,如果是系统时间的问题,mosquitto_connect应该返回TLS校验证书失效的错误提示,而不是阻塞。
  4. 怀疑应用程序其他部分干扰mosquitto_connect的调用流程,使用mosquitto_pub直接向EMQ发布消息,发现现象一样。

上述几轮怀疑和测试之后,调试陷入了僵局,我有些郁闷,经过思考之后,使出了杀手锏:就是最笨的,也是最有效的方法:向mosquitto_connect执行流程插入调试日志。其实,有些时候,看似最笨的方法,却是最为有效的调试方法,只要方向对,花些时间和精力也是值得的。

调试步骤

按照mosquitto_connect的调用流程,增加日志,确定阻塞位置,这里有一个调试的小技巧,就是先主干,再细节,即,先在需要调试的主路径上的关键位置添加日志,然后,编译调试,从而可以确定问题的大体位置,然后,在子流程上再次添加日志,再编译,在调试,这样一步一步递归下去,就会较为快速的定位问题位置。应用该方法,我最终确定了mosquitto_connect阻塞问题位置是:

SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_client_method());

简单介绍一下SSL_CTX_new,其主要是openssl创建用于TLS通信的控制块,为了确认问题,我编写了测试程序,再次确认是不是该函数导致的问题。代码如下:

#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/ui.h>
#include <openssl/ssl.h>void ssl_test(void)
{printf("ssl_test:TP0.\n");SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_client_method());(void)ssl_ctx;printf("ssl_test:TP1.\n");
}

程序很简单,就是为了确认罪魁祸首是不是SSL_CTX_new。Linux开机后,立即执行改测试函数,首先打印"ssl_test:TP0",大约90秒之后,打印"ssl_test:TP1.”,问题位置确认。

发现问题

如果你是一个SSL/TLS机制小白的话,或者说,只了解SSL/TLS交互流程的话,分析SSL_CTX_new的实现原理有点强人所难,我属于这类人,所以,调试再次陷入困境。

就在一筹莫展之际,我发现了一个有趣的现象:发现终端只要打印一行:

random: nonblocking pool is initialized

SSL_CTX_new就会返回,多次测试之后,确认这两者的先后关系。可见,random的初始化和SSL_CTX_new的阻塞存在关系。之后的调试就比较顺利了,实在是山重水复疑无路,柳暗花明又一村

通过查阅资料,发现关于random: nonblocking pool is initialized有以下几种主流的解决思路:

1. Linux随机数nonblocking pool快速初始化

2. random: nonblocking pool is initialized,只是开机不打印该提示,没有实际解决问题

3. Linux随机数nonblocking pool快速初始化

经过分析,1、3和该问题的现象基本一致:可以确定,4.1.15版本的内核random驱动存在问题,导致系统启动时,random初始较慢(90s),而SSL_CTX_new在初始化的时候,用到了random,其需要等待random初始化完成,才能继续执行,从而导致SSL_CTX_new阻塞,最终导致mosquitto_connect阻塞。

解决问题

修改random内核驱动代码:drivers/char/random.c,找到函数add_interrupt_randomness,修改如下的代码:

原始代码:

 if ((fast_pool->count < 64) &&!time_after(now, fast_pool->last + HZ))return;

修改后的代码:

 if ((fast_pool->count < 64) &&!time_after(now, fast_pool->last + HZ) &&nonblocking_pool.initialized)return;

注意:本文内核版本是4.1.15,经过查阅内核代码,发现在较新的内核版本,该bug已解决!

编译,替换内核,经测试问题解决!

后记

反观这个问题的解决过程,不知道你发下了没有,一开始,问题的现象和引起问题的根源,可以用俗语“八竿子打不着”来形容,每次感觉问题快要解决了,最后,还是竹篮打水一场空,那种失落感、焦虑感会越来越浓。其实,事后分析解决问题的过程,不难得出解决问题的关键首先,保持冷静,确定方向,然后,使用科学的方法,坚持不懈的向前推进,相信自己,最后,问题最终会被解决,只是时间的问题

记一次坎坷的调试|Mosquitto通过TLS连接EMQ时阻塞的问题相关推荐

  1. debug —— set args调试命令(作为程序运行时的参数)

    debug调试 -- set  args 作为程序运行时候的参数 set args作为程序运行时参数: 源代码: 1 #include <stdio.h>2 int main(int ar ...

  2. 无法在Web服务器上启动调试。与Web服务器通信时出现身份验证错误

    使用Visual Studio 2005(Visual Studio 2008亦存在此问题)调试设置了主机头的网站时出现如下错误信息: --------- Microsoft Visual Studi ...

  3. mosquitto 开启 TLS 问题总结

    正文 在使用 mosquitto 对 MQTT 开启 TLS 进行测试时,经常会遇到各种神奇的错误,但是 mosquitto 的日志却少的可怜,服务端能看到的日志大约就这几种: SSL routine ...

  4. Android Studio调试之使用USB连接手机调试(详细版)

    环境准备 JDK Android SDK Android Studio 3.x(我的是3.2,3.0以前的版本可能有些区别) 手机一部,可以开启USB调试即可,不用ROOT 手机端 手机上要先开启&q ...

  5. 记一次坎坷的算法需求实现:轻量级人体姿态估计模型的修炼之路(附MoveNet复现经验)...

    点击上方"计算机视觉工坊",选择"星标" 干货第一时间送达 作者丨Fire 编辑丨极市平台 导读 本文记录了作者实现轻量级人体姿态估计模型的全过程,从方案的选取 ...

  6. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(4)- 联合调试(vspd, sscom, PyCharm2018.2)...

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之联合调试. 软件开发离不开调试,调试手段分两种:一是黑盒调试,即直接从输入/输出角度测试软件功能是 ...

  7. 记spi nor flash的调试心得

    flash 调试心得 前言 调试目的 调试步骤 检查 驱动 flash操作 改写 复位 访问模式 tips 内核下相关 文件系统 nor和nand的区别 前言 在工作中或者在开发板上或多或少都会遇到n ...

  8. 记 DNS 解析失败跟踪调试

    昨天下午,运维改完了域名,昨天晚上客服就陆续反映客户端有小部分新老客户登录失败. 运维坚持说,改动的是其它域名,不影响当前客户端. 好吧,客户端工程师只能去问题客户机器上远程查看日志,查看问题. 因为 ...

  9. 记一次坎坷的算法需求实现:轻量级人体姿态估计模型的修炼之路(附MoveNet复现经验) 收藏

    一.需求背景 这天接到个新需求,需要实时检测自然场景下目标人体的关键点位置. 从算法工程师的角度来拆解下需求: 1.检测人体关键点位置,就是人体姿态估计任务嘛: 2.要实时,那么就是终端部署,服务端那 ...

最新文章

  1. iOS开发之用到的几种锁整理
  2. 深度学习巨头Yoshua Bengio清华演讲: 深度学习通往人类水平人工智能的挑战
  3. python对英语和数学的帮助-英语和数学都不好,但是我想学Python编程可以吗?
  4. java获取注解信息_java 自定义注解,获取注解信息
  5. Linux查看网卡UUID另一方法
  6. OpenCV3学习(7.2)——图像分割之二(分水岭算法watershed)
  7. php 代码mysql 读写分离实例
  8. oracle删除导入库,oracle数据库删除和导入方法
  9. B站莫烦Python基础学习笔记
  10. Struts框架实战精讲 struts1(5)- 动态ActionForm
  11. 【微机】ALU的核心就是带标志加法器
  12. 实验室无人机平台 Pixhawk 2.4.8 / PX4 v1.9.2
  13. 微信朋友圈点赞测试用例
  14. sp01事务码_修复了Server 2003 SP2上的“新事务无法在指定事务协调器中登记”
  15. Bridging signals(最长上升子序列)
  16. 快狗打车CTO沈剑:如何利用计划管理提升团队效率和产能
  17. 微信红包封面小程序源码-逢年过节非常火爆
  18. Python下载网易云歌单歌曲,这个脚本你给多少分!
  19. Python execjs(执行js脚本)
  20. 带你快速看完9.8分神作《Effective Java》—— 序列化篇(所有RPC框架的基石)

热门文章

  1. 如何实现模拟量信号远距离无线传输?
  2. 【计算机视觉】深度相机(一)--TOF总结
  3. Hold time 个人理解
  4. angular启动项目报错:ERROR in The target entry-point “primeng/editor“ has missing dependencies:
  5. oracle中如何写函数【oracle技术】
  6. sql数据库表格id重置
  7. 中科院人工智能学院982程序设计在职考研
  8. 找规律:墨菲定律、欧姆定律、帕金森定律、马太效应
  9. 软考-软件设计师】(二). 操作系统
  10. NAP NSP 认证