1. 問題
W5500在實際項目應用時遇到Client可能會異常中斷和板卡的連接。軟件程序控制斷開連接,實際上由於種種原因未斷開,使得板卡進入某種臨界狀態,且無法恢復。根本原因是驅動庫的接收函數爲阻塞型,在沒有報文接收時會阻塞在該函數內部,當外部Client進行某種異常斷開後,Socket的狀態得不到及時更新,認爲當前依然在established狀態,依舊阻塞。而Client恢復後無法再次連接該端口,造成死鎖。
2. 解決
解決辦法是在程序內增加keepalive幀,異常阻塞超過一定時間後讓w5500自動關閉該socket,跳出該阻塞W5500,使能KeepAlive功能分兩種方式:自動發送和手動發送
2.1 準備
使用這種方式前都需要設置一個timeout的時間參數,setRCR()和setRTR()
寄存器方式設置
- setRTR()爲設置超時時間,單位爲5s,一般默認即可
- setRCR()爲設置超時次數,在檢測到網絡上無消息傳送時發送keepalive報文,若無響應超過該次數則關閉socket,進而更新socket的狀態
函數接口方式設置
直接調用ctlnetwork(CN_SET_TIMEOUT, (void *)&gWIZNetTimeout);這個函數,其中第二個參數爲配置值,用戶需指定。
位置:wizchip.c文件中 void network_init(void) line243
wiz_nettimeout.retry_cnt = 5; //1->5
wiz_nettimeout.time_100us = 30000; //200-> 20000 3s
ctlnetwork(CN_SET_TIMEOUT, (void*)&wiz_nettimeout);
->
wizchip_settimeout((wiz_NetTimeout*)arg);
->
void wizchip_settimeout(wiz_NetTimeout* nettime)
{
setRCR(nettime->retry_cnt);
setRTR(nettime->time_100us);
}
2.2 自動模式
初始化時對應的Socket 用setSn_KPALVTR(sn, 0x01); // 配置命令,可以放到系統初始化中
此處W5500芯片有自動處理機制,若在設定時間內有數據收發,則默認不發送keepalive幀。若設置的超時時間爲5s,重試次數爲2次,只要在connect成功後我們保持10S以上不發數據就可以通過wireshark檢測到keepalive幀
2.2 手動模式
手動模式需要設置兩處
- setSn_KPALVTR(sn, 0x00); // 在初始化代碼中放置,第二個參數必須爲0
- IINCHIP_WRITE(Sn_CR(sn),Sn_CR_SEND_KEEP); // 在主循環或定時任務中
這個是手動發送的,只要執行第二條指令就會發送出 keepalive幀,不管這個週期內有無數據