1.问题场景描述
本机运行LWIP协议栈,作为TCP客户端负责接收数据,上位机使用标准TCPIP协议栈并使用socket套接字,作为服务器端按照100ms周期向客户端发送数据。通信链路为千兆以太网,且整个网络仅有两个节点。在数据交互的过程中发现,客户端的TCP链接不稳定,频繁与服务器端断开链接,无法正常接收服务器端的数据。
2.问题分析与排查
由于服务器端是使用标准socket套接字编程,且经过长期验证,因此问题出现点大概率为使用LWIP协议栈的客户端。排查过程中,首先将服务器端的数据速率由100ms降低为1s,结果发现客户端的链接基本稳定。然后,在上位机运行wireshark进行抓包分析,发现即使是在1s周期的条件下,服务器端发送的数据包并未收到客户端返回的ACK包,结果导致服务器端重传相同的数据包;将发送速率恢复到100ms周期后,发现服务器端由于未收到ACK包而大量地重传数据包,由于重传到一定量后服务器端仍旧未收到ACK包,因此服务器端主动关闭了该链路,也就说明了为什么客户端会发现链接不稳定。
3.问题解决
通过上述排查分析,基本可以定位到是由于客户端在收到报文后未向服务器端正确回复ACK报文导致的,因此查看客户端的LWIP TCP接收回调函数,发现内部确实没有任何返回ACK报文的语句。同时查找LWIP TCP相关资料,发现某些配置下,在接收到数据报文后并不会主动发送ACK报文,而是等待发送数据时将ACK一并带出。巧合的是,测试时客户端仅接收数据并未发送数据,所以就会出现不发送ACK的现象。通过查阅LWIP函数接口,发现了tcp_send_empty_ack()函数,从字面意思就能知道该函数的作用时发送一个空的ACK报文。因此在TCP接收回调函数中,收到数据报文之后,调用该函数进行主动发送ACK报文。添加后,发现在100ms或者更快的发送周期条件下,服务器端都能正常接收到来自客户端的ACK报文,从而不会频繁重发数据包。同时客户端的链接也稳定,不再出现频繁断开与服务器之间的链接的情况。
后记
出现网络问题,要及时使用wireshark等抓包工具进行抓包协助分析。其次,还要想办法搭建便于测试分析的测试环境,提高问题排查的效率。最后,还要进一步加强对TCPIP协议的深入学习与研究,打好基础才能快速分析定位问题。