TCP連線被意外重置的原因

2021-04-20 07:38:39 字數 2405 閱讀 2258

今天在做伺服器壓力測試的時候,出現了很奇怪的情況,與伺服器建立連線會成功,但是很快會被重置(reset)掉。花了半天時間,終於找到原因所在,我把過程和結果寫下來與大家分享。

伺服器正常邏輯是:接受連線,等待使用者註冊報文,處理其他請求,如果連線一段時間沒有活動,則主動關閉連線。

客戶端邏輯是:與伺服器建立連線後,馬上傳送註冊報文,然後每隔一段時間傳送乙個請求。有上萬個客戶端同時連線乙個伺服器,當連線出現錯誤時,馬上重新連線。

出現錯誤時,客戶端會報告下面一連串錯誤:

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

recv: connection reset by peer

進一步的測試發現只有在客戶端數目超過一定數量才會出現這樣的情況,於是聯想到linux程序開啟檔案描述符(linux下套接字也是一種檔案描述符)的數量限制(前幾天剛剛增加了這個數量限制),但是到底有什麼聯絡不知道。

開始以為伺服器程式邏輯主動關閉了連線,但是根據抓包的結果,伺服器根本就沒有傳送tcp fin報文,下面是乙個典型的連線建立與重置的過程:

14:01:03.567888 ip 192.168.6.45.36692 > 192.168.6.46.8080: s 1231228012:1231228012(0) win 5792

14:01:03.567969 ip 192.168.6.46.8080 > 192.168.6.45.36692: s 909133089:909133089(0) ack 1231228013 win 5792

14:01:03.567978 ip 192.168.6.45.36692 > 192.168.6.46.8080: . ack 1 win 23

14:01:03.568022 ip 192.168.6.45.36692 > 192.168.6.46.8080: p 1:76(75) ack 1 win 23

14:01:03.568110 ip 192.168.6.46.8080 > 192.168.6.45.36692: . ack 76 win 23

14:01:03.568769 ip 192.168.6.46.8080 > 192.168.6.45.36692: r 1:1(0) ack 76 win 23

檢查伺服器的日誌,也沒有主動關閉連線的記錄,甚至並沒有接受到新的連線。這說明連線是由底層協議棧關閉的,但協議棧為什麼會主動關閉呢?

用telnet連線伺服器,也不正常,但是是被正常關閉的(有正常的fin序列),而不是重置。

是否與偵聽套接字的就緒連線佇列長度有關?但是連線佇列滿時,協議棧不做任何操作,而是讓客戶端超市重發syn報文,與出現的情況不一致。

看來還是有開啟檔案描述符的數量限制有關,那麼不能再開啟檔案描述符時,會出現什麼情況呢?為什麼telnet連線會出現不同的情形呢?對這些問題的回答就要透過現象看本質了,我的分析如下:

首先,連線確實是建立了,說明協議棧是接受了這個連線的,當然,應用程式肯定沒有接受,否則開啟檔案描述符數目超過上限了。另一方面,協議棧當然要關閉這個連線,但是沒有立即關閉,應該是在應用程式接受連線時(accept)關閉(尚未驗證),進一步跟蹤,accept會產生too many open files錯誤。這也說明套接字這個檔案描述符是在accept時開啟的,在協議棧中建立的連線並沒有對應的套接字描述符。

telnet連線的不同之處在於沒有向伺服器傳送資料,此時採用正常方式關閉,這是協議的要求還是linux實現的特例沒有考證過。

還有另外乙個結論是在accept之前收到的資料仍然會被接受並應答,並且連線上的資料是儲存在協議棧中的,這符合我先前的概念。

TCP連線意外中斷

如何及時有效地檢測到一方的非正常斷開,一直有兩種技術可以運用。一種是由tcp協議層實現的keepalive,另一種是由應用層自己實現的心跳包。tcp預設並不開啟keepalive功能,因為開啟keepalive功能需要消耗額外的寬頻和流量 建立連線以後用kill殺死伺服器程序,作為程序終止處理的部分...

wcf 基礎連線已經關閉,連線被意外關閉

專案中在使用wcf返回資料時,發現一直報這個錯誤 基礎連線已經關閉,連線被意外關閉 經檢查後,發現 沒有什麼問題,只是乙個簡單的查詢,除錯的時候,發現返回的資料量比較大6000多個,後面在想,是不是資料量太大的原因,把返回的資料改少些,馬上就成功了!那ok了,起碼知道問題出在 出現這個問題主要是因為...

Linux下http連線被重置的實驗性解決辦法

首先讓我為大家介紹一下這個問題的背景知識。典型tcp資料報有乙個最大視窗大小為64kb的視窗域。這在網際網路發展初期,大部分系統都沒有能力處理比這更大的資料,因此這個大小是足夠的,但是對於現在的接入頻寬應用來說,這已經太小了。為了解決這個問題,1992年提出了一種稱為視窗縮放的解決方案,它提供了乙個...