IPC摄像头在线状态ping检测与告警邮件发送项目总结

目录

1、项目背景与需求

2、技术实现思路

3、libcurl开源库的编译

3.1、尝试使用现成的libcurl库

3.2、7.32.0版本 libcurl库的编译

3.3、7.54.0版本 libcurl库的编译

4、调试中遇到的问题

4.1、调试退出程序时的内存泄漏

4.2、使用string类对象给函数传递字符串参数要加上.c_str()

4.3、当前运行调试程序的PC的IP被邮箱服务器锁死了

4.4、用搜狐邮箱的邮件服务器就有问题

4.5、调用API函数IcmpSendEcho发送ping包,该如何判断有没有ping通对方

5、发布的程序到客户的机器上运行 错

5.1、 错情况

5.2、 错分析

5.3、编译release版本的libcurl

6、告警邮件发送到客户的163企业邮箱有问题

7、最后


      今天将以前做过的一个小项目的经历与总结,分享给大家,希望能给大家提供一个借鉴或参考!项目中主要涉及两个功能点,一是通过ping检测IPC监控摄像头是否在线,二是使用libcurl开源库发送设备不在线的告警邮件。下面将讲述了整个项目的开发调试过程,并对遇到的问题进行了详细的总结。

开发工具:Visual Studio 2010

开发语言:C++

1、项目背景与需求

       项目背景是这样的,客户使用了一个国外厂商的视频监控系统,视频管理平台可以监控到前端IPC摄像头的在线状态(使用软件间的心跳检测),但检测到IPC摄像头异常后,视频管理平台无法将告警信息发送到客户的163企业邮箱中,即视频管理平台的发送邮件功能有问题,调试了很久始终没有解决。

       客户坚持要使用他们的163企业邮箱接收告警信息,并且客户要求尽快解决这个问题,这个问题解决后才能对整个项目进行验收!如果将这个需求反馈给国外的开发人员,来来回回会折腾很久,问题能不能彻底解决还不好说。

       后来项目方公司领导想到一个临时替代办法,可以采用ping IPC摄像头的方式,简单地判断设备是否出 络故障。如果IPC摄像头ping不通,可能IPC摄像头设备是出问题了,然后将故障告警信息发送到指定的163企业邮箱中。

       于是找到我,帮他们开发这个小工具,具体需求点如下:
(1)IPC设备管理

       支持对IPC摄像头设备的管理,添加IPC摄像头的设备名称、设备ip,支持设备的增删改;这些设备信息保存在本地即可。

(2)对IPC设备的ping检测

       对添加的IPC设备开启多线程进行检测,通过ping设备的IP地址,检测设备是否出 络故障,ping失败次数达到设定上限后,则认为设备出现 络故障了。

(3)发送IPC设备异常告警的邮件

       检测出设备 络异常,通过公用的smtp服务器或者客户自己的邮箱系统自带的smtp服务器将故障信息邮件发到指定的163企业邮箱中进行告警。该软件中要支持配置smtp邮件服务器地址、发送告警信息的邮箱地址,以及接收告警邮件的邮箱地址。要支持发送测试邮件,判断当前的配置能否正常发送邮件。

2、技术实现思路

(1)ping功能实现
        最开始想到使用裸socket,调用sendto和recvfrom,自己构造ping包的数据头,但是这个裸socket在windows上需要管理员权限,在win7及以上系统上会弹出UAC提示框,客户使用起来会比较麻烦。
       因为windows上裸socket需要管理员权限,而linux上没有这个问题,所以研究了一下windows上有没有替代方案,找到了IcmpSendEcho API函数,可以实现ping包的发送与回复检测。但是发ping包,ping包在公 上跑可能会被路由器等 络设备拦截掉,所以发ping包的方法也不太保险。后来还是决定使用这个方法,因为管理软件和前端IPC摄像头运行在同一个局域 中, 络环境比较简单,不会走公 ,所以不会有数据包被拦截的问题。
(2)发送邮件功能实现
       到 上搜索到发邮件常用的smtp协议,找到了一些代码,但这些代码是直接使用socket api实现的,比较简单,虽然包含了smtp的基本协议,但都是先send马上recv,缺少对 络及协议交互的异常处理,很不可靠,很不稳定,根本没法用的。经过测试发现,邮件有的成功有的失败,会经常发送不成功。   

       后来搜索发现,可以使用开源库libcurl中支持smtp协议的邮件发送功能,编写了相关测试代码测试了一下,确实是有效果的。使用朋友自己的webmail smtp服务器进行测试,每次都能发送成功,比之前 上搜到的简单代码要靠谱的多。所以决定使用开源库libcurl来实现发邮件的功能。

3、libcurl开源库的编译

3.1、尝试使用现成的libcurl库

       本来这个小项目急着用,以关键字curl到平时做过的代码目录中搜索了一下,看看之前的项目中有没有libcurl库的工程,可以直接拿来使用,就不用花时间去研究开源库libcurl的编译了。因为直接到libcurl官 上下载源码,编译和配置估计比较麻烦,会比较耗时。

       在之前的项目中搜到了现成的libcurl库后,将之拿到当前的工程中测试,结果调用发送邮件的接口curl_easy_perform返回失败了,返回的错误码为CURLE_UNSUPPORTED_PROTOCOL,难道是当前使用的版本库不支持SMTP协议/p>

       按讲不应该啊,SMTP协议是libcurl开源库官方支持的啊!查看代码才发现,原来是之前有人使用CURL_DISABLE_SMTP和HTTP_ONLY宏将SMTP、FTP、telnet等不用的协议都裁剪掉了,只保留了主要的HTTP功能,其他协议的.c文件也从项目工程中删除了,但磁盘上还是有的。
       于是尝试着将SMTP等协议功能添加进来,将DISABLE宏注释掉,编译libcurl,提示链接不到SMTP模块的接口。后来发现smtp.c没有添加到工程中,即smtp.c没有编译,所以链接不到SMTP模块的接口。

        但加进去后编译还是有问题,来回试了好几次还是不行,所以不得不到官 上下载新版本的libcurl,搜索libcurl的编译配置方法,只能使用官方的代码编译出libcurl库文件了。

3.2、7.32.0版本 libcurl库的编译

       当下只能去libcurl的官 下载最新版本的源码,自己来编译了。官 最新版为7.54.0,下载到源码包,但这个压缩包的curl-7.54.0projectsWindows路径下VC6-VC14各个版本的VS解决方案,在打开后编译,会提示找不到openssl相关的头文件:

即libcurl库依赖到了openssl,但本地找不到openssl的相关文件,所以 出上面的错误。

       于是需要下载openssl来手动安装配置一下。配置openssl有两种方法,一种是下载安装包直接安装(就像使用WindowsSDK包一样),一种是将openssl的代码下载下来编译配置。当然是前者最简单,可以去搜索Windows下openssl的下载安装和使用说明。但是因为时间比较紧,要抓紧实现并测试效果,所以就没时间去配置安装openssl并编译新版本的libcurl。正好看到相关文章,得知7.32.0版本(某个阶段的老版本,不是最新版本)是可以直接拿来用VS2010编译的,于是到官 上去下载7.32.0版本。根据文中的说明,可以很快将libcurl编译出来并加以使用。

3.3、7.54.0版本 libcurl库的编译

       后来有时间的时候,研究了一下最新版7.54.0 libcurl库的编译。7.54新版本的libcurl新增了openssl库的依赖,需要事先配置openssl才能编译通过。另外,还需要libssl,也需要事先部署一下。

        因为编译openssl之前要下载perl脚本工具,要处理makefile文件,比较复杂,可以选择下载openssl的安装包,手动安装。libcurl包含了openssl的头文件,引入了openssl的lib和dll库,所以要从openssl安装目录下拷贝头文件和库文件到我们的工程目录下。对于依赖的libssl库,则比较简单,直接到官 上将开源代码下载下来编译即可。

4、调试中遇到的问题

4.1、调试退出程序时的内存泄漏

       代码写好后,对代码进行调试,发现退出时有较多的内存泄露。按讲不应该啊,代码中基本没有new和malloc,不应该有内存泄露。更为奇怪的是,竟然提示stl的string类有泄露,这个类的内存应该自管理的,是Visual Studio(后面简称VS)官方的类,肯定是没有问题的。

       内存泄露对于长时间运行的监控程序是致命的,必须要解决掉,但是通过现有现象看感觉很诡异。根据退出时VS的提示,很多泄露发生在发送邮件的类CSmtpSendMail中,这个类中的成员都是string类型的变量,将发送邮件的代码注释掉,重新测试了下,就没有泄漏了。

       后来想到,可能是监测线程的代码中sleep了30分钟(配置中配置了扫描间隔为30分钟),但是中途尝试退出程序时会先将启动的监测线程退出来,具体的做法是:将线程中的表示变量m_bStart置为FALSE,让监测线程函数自己退出,然后wait 5秒中,如果没有自动退出,则手动调用TerminateThread API函数将线程直接terminate掉。

       因为sleep 了30分钟(软件中支持设置ping设备的间隔时间,间隔时间设置为30分钟),所以监测线程没有自动退掉,所以被我们强行terminate掉了,而此时可能正在运行发邮件的代码,导致发邮件的对象类没有正常析构,所以导致成员string类对象中的内存没有正常释放,从而导致了内存泄漏。

       其实,是代码写的有问题,即便是sleep 30分钟,也要保证在m_bStart设置为FALSE时能及时退出线程,具体做法将间隔时间分成比如50ms因子若干倍m,然后for循环将50ms因子的sleep执行m次,每次执行sleep 50ms之前,检查一下m_bStart是否为FALSE,是FALSE说明当前要退出线程,直接退出sleep循环,让线程函数尽快退出,线程函数退出了,线程就结束了。

4.2、使用string类对象给函数传递字符串参数要加上.c_str()

      调用CSmtpSendMail::SendMail函数发送邮件失败,调试发现是curl_easy_perform函数返回失败,返回CURLE_COULDNT_RESOLVE_HOST错误码,即不能解析出smtp服务器域名地址。一般smtp邮件服务器的地址都写成域名,所以libcurl库内部在连接之前需要进行域名解析。后来发现,需要将传递给curl_easy_setopt函数的参数由tmp改成tmp.c_str(),因为传递的应该是一个字符串。有问题的代码如下:

将tmp改成tmp.c_str()就正常了。

4.3、当前运行调试程序的PC的IP被邮箱服务器锁死了

       用同学自己搭建的开源的webmail邮件系统测试邮件发送功能。上午测试的还好好,每封邮件都能发出来,下午测试的时候就连不上服务器了,这个就奇怪了,上午还好好的,下午怎么就有问题了呢道是邮件服务器挂掉了strong>调试程序连不上,使用同学给的web邮箱服务器主页地址,在浏览器中也打不开。

       与同学沟通后,猜测可能是ip被锁住了,禁止登录了。用手机移动数据访问是能打开的,应该是电脑ip被锁住了。于是登录到路由器上,断开 络连接,重新连接后宽带运营商给路由器重新分配了ip地址就能发送邮件了。

       这个IP限制,在某些视频 站上也有,比如 站限制当前PC只能看几个视频,超过数目限制,就不能观看了。此时,可以试试登录路由器挂断拨 ,重新连接,运营商重新分配了一个IP就好了。有时,可能换IP还不行,还要清理浏览器缓存,然后用360清理一下系统才行。

       至于为什么IP被锁死,不是很确定,可能是我们发送测试邮件的某些行为触发了邮箱服务器上设定某些安全规则,服务器将从PC的IP地址上发过来的数据包直接拒绝掉,比如多次密码输入错误,服务器会锁死ip一段时间,因为系统要将穷举法盗取密码的行为遏制住。邮箱有很多安全策略,比如短时间内发大量的邮件会触发规则。

4.4、用搜狐邮箱的邮件服务器就有问题

       开源的libcurl要好很多,使用同学的webmail给163发送邮件,每次都能发送成功。但使用搜狐的邮箱服务器(注册了一个搜狐邮箱,登录后在设置中启用了smtp服务)给163邮箱发,却是时而成功,时而失败。

       后来和海康威视的监控客户端对比了一下(占据视频监控市场份额全球第一的海康威视,他的客户端是可以在其官方下载,免费登录,免费使用的),海康的客户端设置中有设置邮件的功能,支持发送测试邮件,如果使用搜狐的smtp邮件服务器也有类似的情况。这样对比下来看,可能搜狐邮箱系统的smtp服务是有问题的。
       后来使用126的服务器给163的邮箱发送测试,海康能发送成功,但我们的有问题,查看返回的错误码是向对端发送数据失败。这有点奇怪,难道海康用的是libcurl的multi接口,回头可以用api monitor监测一下。

4.5、调用API函数IcmpSendEcho发送ping包,该如何判断有没有ping通对方

      从msdn上查看IcmpSendEcho系统API函数的说明:

查看该函数返回值的说明,返回值为0,则表示失败。通过MSDN上给出的示例代码也能看出来是这样的:

但测试发现,添加一个不存在的IP地址,IcmpSendEcho有时会返回0,有时会返回非0,所以不能通过IcmpSendEcho的返回值来判断是否是能ping同对方了。
       于是百度了一下IcmpSendEcho函数,在百度百科中找到了一个很有用的说明:

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年4月27日
下一篇 2022年4月27日

相关推荐