最近在项目中遇到一些小小的问题,犯过的错希望不要犯二次。我Linux环境下开启一个TCP服务和FTP客户端用来升级系统,正常情况下是没任何差错的,如果断网(拔网线)或者PC端升级软件(QT软件)崩溃(强行退出),系统就会出现问题,
流程有2个,一个是FTP下载过程,一个是Flash写入过程,都涉及进度值的上传,即无时无刻都在调用write函数,并且进度函数的返回值是不处理的,也是没有任何函数来处理检测此函数是否正常运行的,主要是没法处理接收。
FTP下载CURL设置: 进度函数部分
TCP在正常网络下是“三次握手,四次挥手”,服务器和客户机分别正常退出处理是没什么问题的。
一、如果突然断网了,PC端TCP客户机不会发任何信息,可能出现的问题有:
①此时如果还处于TCP命令交互过程,可添加keepalive机制(只开启设置当前套接字的keepalive属性),保证规定时间内没有回响可关闭套接字,等待下一次连接。注意不能更改Linux整个系统的keepalive值
系统keepalive值可通过sysctl -a 或者 sysctl -a |grep tcp_keepalive* 查看
当前tcp套接字keepalive设置代码:
②此时如果处于FTP下载过程中,curl库会一直卡死在那里,无法自动退出来(curl设计机制问题,没法更改),但是进度函数里面write不会报错(断网情况下返回值不为-1),导致此更新进程模块废掉,只能重启,解决办法可以添加curl下载超时限制CURLOPT_TIMEOUT,该延时表示多久到了文件还没有下载完成curl就会自动断开重新连接下载,由于断网,此时连接超时(CURLOPT_CONNECTTIMEOUT)将会自动退出,从而可以正常处理,程序如下
curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 120);
此语句缺点就是不管多大文件,只给你120S的下载时间,如果文件过大,120S下载不完,那么一直死循环下载会出问题,所以不到万不得已不要使用,由于项目实际文件最大的才6M多点,一般正常网络情况下30s内可解决战斗,遇到网络不好的可能时间长点,
此延时时间设置太大也不行,没有及时性,都出问题了,你不可能让客户等很长时间吧?客户还以为更新失败成砖了,直接报废处理了。
③此时处于写入过程中时。进度函数中write也不会出错,也没法接收,就让它写完再在FTP连接的过程中失败退出吧。
二、若果上位机突然崩溃了,此时window 系统会回收套接字,给tcp服务器端发送一个RST信号,此时Linux下面处于集中情况:
①此时如果还处于TCP命令交互过程中,与上一样,有keepalive机制,规定时间内可以自动断开,等待下一次连接。
②此时如果处于FTP下载过程中,由于进度函数不断被调用,不断循环(curl设置1S时间调用进度函数一次)调用write函数上发数据,上面崩溃时也会不断被调用,第一次调用write会返回-1,第二次再调用write就会阻塞卡死在write这里(这个地方吃了大亏),不得不吐槽curl库,既然FTP服务器端都没了,出问题了,客户端怎么还是不停的调用进度函数?上面提到了curl中是不涉及处理进度函数返回值的,管你是不是出错,这时候没办法啊,既然出错了,我的要赶紧退到初始调用FTP下载到的地方吧?怎么办?在函数之间进行跳转的恐怕只有setjmp() / longjmp()吧?C语言错误异常跳转特殊函数,与函数AR地址相关的,比goto还厉害的语句。
在最最开始顶层的地方设置如下:
AbnormalFlag = setjmp(Ftpdown_jb);
if(AbnormalFlag == 0 )
{
/* null */
}
else if(AbnormalFlag == 1 )
{
Enter setjmp Ftpdown_jb abnormar
FileSuccessAllFlag = 0;
goto end;
}
else
{
/* null */
}
ret = FtpDownload(***);
然后在进度函数中write中写入如下
ret = write(G_sock_c,SendBuff,ret);
if(ret < 0)
{
****
longjmp(Ftpdown_jb,1);
}
write第一次出错,保证能退出来,实现函数隔层之间的的跳转,然后释放当前套接字,等待下一次连接。
③此时处于flash过程与上同理处理。
好了,写了这么多,有不严谨之处还请指教。
原文地址:https://www.cnblogs.com/YWX888/p/11057957.html