TCP连接异常处理
Netty使用TCP連接錯誤
歡迎關(guān)注驛外殘香 | HC的博客
表面原因
在與嵌入式組進行TCP連接時發(fā)生未知錯誤導致服務器接收不到數(shù)據(jù)。并且Netty封裝的exceptionCaught方法以及channelInactive方法捕獲不到任何的報錯異常以及連接斷開情況。
探尋主線
一開始使用tcpdump -iany tcp port 8090對8090端口進行抓包,發(fā)現(xiàn)在經(jīng)過三次握手之后服務器與客戶端之間就開始了一來一往的包傳遞,在經(jīng)過了幾個小時之后,包之間的傳遞戛然而止,查看最后幾個包的信息,并沒有看到有關(guān)斷開連接的四次握手操作。
Linux操作環(huán)境中使用lsof -i:port檢測打開套接字的狀態(tài)。發(fā)現(xiàn)除了一條用于監(jiān)聽8090端口連接的線程外,該端口還建立了多條處于ETABLISHED狀態(tài)的線程。
由于客戶端只有一個,在查閱了資料發(fā)現(xiàn)在一臺客戶端與服務器的TCP連接中,處于連接狀態(tài),即ETABLISHED狀態(tài)的線程應該只有一條。
于是嘗試使用kill -9 port殺死了目前正在運行的Java項目,同時可以觀測到除了監(jiān)聽線程被關(guān)閉外,其他8090端口的線程都處于FIN-WAIT-1狀態(tài),即正在等待客戶端返回ACK與FIN。但很明顯,客戶端沒能夠返回該信號而導致該線程一直處于該狀態(tài)。直到幾分鐘過去了,服務器強制關(guān)閉了這些線程。
此處查看了網(wǎng)絡上的資料,發(fā)現(xiàn)當服務器出現(xiàn)很多ESTABLISHED狀態(tài)時,可能是這時候若客戶端斷開的時候未發(fā)送FIN包,則服務端處還是顯示ESTABLISHED狀態(tài);
結(jié)果客戶端重新連接服務器。而新連接上來的客戶端(也就是剛才斷掉的重新連上來了)在服務端肯定是ESTABLISHED;
如果客戶端重復的上演這種情況,那么服務端將會出現(xiàn)大量的假的ESTABLISHED連接和CLOSE_WAIT連接。最終結(jié)果就是新的其他客戶端無法連接上來,但是利用netstat還是能看到一條連接已經(jīng)建立,并顯示ESTABLISHED,但始終無法進入程序代碼。
這時想起最初的時候嵌入式組為了防止服務器的斷線,每隔幾分鐘便斷開連接并重新連接。此時可能由于網(wǎng)絡上的問題,導致斷開的信息服務器未能接收到,這樣就造成了上述的情況。在本地電腦跑的時候沒有這么頻繁的斷開事故可能就是網(wǎng)絡的原因。
那么阿里云的網(wǎng)絡有這么差么?經(jīng)過下面測試。。emmm。。看來發(fā)送個幾百條斷開信號但因為網(wǎng)絡原因漏掉幾條也沒什么不對的。。
解決方案
使用正則表達式對嵌入式發(fā)送的數(shù)據(jù)進行匹配,若發(fā)現(xiàn)不符合數(shù)據(jù)格式則拋出異常并斷開連接,防止影響后面的數(shù)據(jù)庫操作。
\b\w*:V_\d:[0-9]+[.][0-9]*,I_\d:[0-9]+[.][0-9]*,P_\d:[0-9]+[.][0-9]*,PF_\d:[0-9]+[.][0-9]*,F_\d:[0-9]+[.][0-9]*,W_\d:[0-9]+[.][0-9]*\bend與嵌入式端協(xié)調(diào),取消每隔幾分鐘斷開重連的機制。
使用心跳機制,當服務器在一定時間內(nèi)沒有接收到客戶端發(fā)來的信息時則斷開連接,同時在接收到客戶端信息的同時發(fā)送響應信息,讓嵌入式方面進行相應的操作。
總結(jié)
- 上一篇: P1047 校门外的树
- 下一篇: 模型遥控器制式说明