各位进来讨论一下lwip 常时间停留FIN_WAIT_1状态的bug

发布于 2020-05-07 10:13:05
最近在测试rt thread 3.1.3 + lwip2.0.3版本的程序,硬件是STM32F429 + LAN8720,即正点原子的阿波罗开发板。
故障现象:应用程序编写一个tcp服务器的程序,在电脑端启动一个tcp客户端向服务器发送数据,服务器接收到后返回数据,经过几天的测试,通信的稳定性不错了,就是通信速度还待优化提升一下。

tcp测试.jpg
这时拔下网线,在msh接口,执行命令tcpserver --stop 关闭开发板上的服务器程序连接。再输入netstate 查看lwip链接的状态,发现链接并不能马上关闭,如下图,链接处于FIN_WAIT_1状态,要过很长的时间才能关闭释放。经过查看lwip的源程序,tcp.c程序中的981行 tcp_slowtmr函数完成了tcp连接的超时释放处理,函数处理FIN_WAIT_1状态的链接,根据tcp连接关闭的4次握手操作,服务器(开发板)发送FIN_WAIT_1后,等待客户端(电脑)应答ACK进而转入FIN_WAIT_2,由于网线断开,服务器(开发板)程序收到不ack而处于FIN_WAIT_1状态。tcp_slowtmr函数中处理这个状态的超时是按照tcp数据重发逻辑进行的,即采用超时后指数级时间退让再进行下一次数据发送,这个时间总的算下来,可达10多个分钟或更久。

dfef.jpg 20170519213345831.png
经过查看lwip网站,此问题已经相关开发者在去年就提出过,bug的网址:
tcpbuf.jpg
开发者提出的修改建议并没有得到lwip作者的赞同,原因是作者认为这样修改会违背tcpip协议的标准,但是这种bug确实在实际应用中容易出现,并且不能允许这个tcp连接长时间不释放而无法建立新的连接。
我个人建议采用讨论中修改办法,即在 tcp_slowtmr函数中增加对FIN_WAIT_1状态的超时处理。如下图标示的修改方法。
modify.jpg
请各位进来讨论一下,看看有没有更好的办法能解决此问题?

查看更多

关注者
0
被浏览
714
5 个回答
fovery
fovery 2021-04-11

遇到了同样的问题,我是tcp server,有很多从设备,当直接断电从设备后,应用层没有心跳包后,我主动close掉socket,但socket仍然处于FIN_WAIT_1状态,并占用TCP PCB。
当从设备再次上电后,会发现没有足够的TCP PCB可用。

我的更改方案:

方案1

将tcp_slowtmr()中这条语句更改:

/* Check if this PCB has stayed too long in FIN-WAIT-2 */
    if (pcb->state == FIN_WAIT_2) {

更改为:
if (pcb->state == FIN_WAIT_2 || pcb->state == FIN_WAIT_1) {

方案2

直接将lwipopts.h的宏定义TCP_MAXRTX值12改小为4,这样拔掉网线后重发4次就会自动删除掉PCB,此时用户应用层的recv()会接收到返回-1的事件,用户再close掉已删除了PCB的socket。
#define TCP_MAXRTX 12
更改为:
#define TCP_MAXRTX 4

推荐用方案2,因为这样不改动lwip内部,仅改动了配置参数,并且也符合TCPIP协议的规范。

sync
sync 2020-05-11
好帖,只是能力有限,帮顶下了
aozima
aozima 2020-05-11
拒绝白嫖,拒绝键盘侠!
把这个超时改得很短也能尽可能的避免这个问题。
fhqmcu
fhqmcu 认证专家 2020-05-11
好帖,只是能力有限,帮顶下了

谢谢,你可以记下这个问题及解决办法,以后要开发以太网也会遇到这样的问题。

whj467467222
whj467467222 认证专家 2020-05-11
好帖,只是能力有限,先收藏了。

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览