TCP復位報文段與常見網路連線錯誤

2021-08-27 17:36:44 字數 3263 閱讀 4578

unable to connect to remote host: connection refused

read error: connection reset by peer

connection closed by foreign host

特別是前兩個錯誤描述,相信很多人都碰到過,但是最底層原因到底是什麼呢?其實這都跟復位報文段有關。復位報文段是指rst標誌生效的tcp包,復位報文段的產生場景有以下幾種。

一:unable to connect to remote host: connection refused

出現這種錯誤,是因為有不存在的埠的連線請求,當連線請求到達時,目的埠沒有程序正在聽。對於udp,當乙個資料報到達目的埠時,該埠沒在使用,它將產生乙個icmp埠不可達的資訊。而tcp則使用復位。產生這個例子也很容易,我們可使用telnet客戶程式來指明乙個目的埠沒在使用的情況:

上圖說明了試圖在不存在的埠上開啟連線而產生的復位。該場景的復位報文段有以下幾點特性:

ack標誌沒有被設定為1

序號被置為0

確認序號被置為進入的isn加上資料位元組數

儘管在到達的報文段中沒有真正的資料,但syn位元從邏輯上占用了1位元組的序號空間;因此,在這個例子中復位報文段中確認序號被置為isn與資料長度(0)、syn位元所佔的1的總和。

二 :read error: connection reset by peer

這是因為異常終止乙個連線

正常終結

正常的終止連線方式是一方傳送fin,即常規的4次揮手,有時這也稱為有序釋放(orderly release),因為在所有排隊資料都已傳送之後才傳送fin,正常情況下沒有任何資料丟失。

異常終結

但也有可能傳送乙個復位報文段而不是fin來中途釋放乙個連線。有時稱這為異常釋放(abortive release)。異常終止乙個連線對應用程式來說有兩個優點:

(1)丟棄任何待發資料並立即傳送復位報文段;

(2)rst的接收方會區分另一端執行的是異常關閉還是正常關閉;

使用sock程式能夠觀察這種異常關閉的過程,socket api通過「 linger on close」選項(solinger)提供了這種異常關閉的能力。我們加上- l選項並將停留時間設為0。這將導致連線關閉時進行復位而不是正常的fin。我們連線到處於伺服器上的sock程式,並鍵入一輸入行:

bsdi % sock -l0 svr4 8888

這是客戶程式,伺服器程式顯示後面

hello, world   

鍵入一行輸入,它被發往到另一端

^ d  

鍵入檔案結束符,終止客戶程式

圖1 8 - 1 5是這個例子的tcpdump輸出顯示(在這個圖中我們已經刪除了所有視窗大小的說明,因為它們與討論無關)。

第1 ~ 3行顯示出建立連線的正常過程;

第4行傳送我們鍵入的資料行( 12個字元和unix換行符);

第5行是對收到資料的確認;

第6行對應為終止客戶程式而鍵入的檔案結束符,由於我們指明使用異常關閉,而不是正常關閉(命令列中的- l 0選項),因此主機bsdi端的tcp傳送乙個rst而不是通常的fin。

rst報文段中包含乙個序號和確認序號。需要注意的是rst報文段不會導致另一端產生任何響應,另一端根本不進行確認。收到rst的一方將終止該連線,並通知應用層連線復位。

我們在伺服器上得到下面的差錯資訊:

這個伺服器程式從網路中接收資料並將它接收的資料顯示到其標準輸出上。通常,從它的tcp上收到檔案結束符後便將結束,但這裡我們看到當收到rst時,它產生了乙個差錯。這個差錯正是我們所期待的:連線被對方復位了。

三:檢測半開啟連線

半連線都會被復位掉,如果一方已經關閉或異常終止,而另一方卻還不知道,這樣的tcp連線稱為半開啟(half - open)的。任何一端的主機異常都可能導致這種情況。只要不打算在半連線上傳輸資料,仍處於連線狀態的一方就不會檢測另一方已經出現異常。

半開啟連線的另乙個常見原因是當客戶主機突然掉電而不是正常的結束客戶應用程式後再關機。這可能發生在使用pc機作為telnet的客戶主機上,例如,使用者在一天工作結束時關閉pc機的電源。當關閉pc機電源時,如果已不再有要向伺服器傳送的資料,伺服器將永遠不知道客戶程式已經消失了。當使用者在第二天到來時,開啟pc機,並啟動新的telnet客戶程式,在伺服器主機上會啟動乙個新的伺服器程式。這樣會導致伺服器主機中產生許多半開啟的tcp連線。

能很容易地建立半開啟連線。在bsdi上執行telnet客戶程式,通過它和svr4上的丟棄伺服器建立連線。我們鍵入一行字元,然後通過tcpdump進行觀察,接著斷開伺服器主機與乙太網的電纜,並重啟伺服器主機。這可以模擬伺服器主機出現異常(在重啟伺服器之前斷開乙太網電纜是為了防止它向開啟的連線傳送fin,某些tcp在關機時會這麼做)。伺服器主機重啟後,我們重新接上電纜,並從客戶向伺服器傳送另一行字元。由於伺服器的tcp已經重新啟動,它將丟失復位前連線的所有資訊,因此它不知道資料報文段中提到的連線。tcp的處理原則是接收方以復位作為應答。

圖18 - 16是這個例子的tcpdump輸出顯示(已從這個輸出中刪除了視窗大小的說明、服務型別資訊和mss宣告,因為它們與討論無關)。

第1 ~ 3行是正常的連線建立過程

第4行向丟棄伺服器傳送字元行「 hithere」

第5行是確認

然後斷開svr4的乙太網電纜,重新啟動,並重新接上網線。接著從客戶端輸入下一行(即「 another line」),當我們鍵入回車鍵後,這一行被發往伺服器(圖18 - 16的第6行)。這導致伺服器產生乙個響應,但要注意的是由於伺服器主機經過重新啟動,它的arp快取記憶體為空,因此需要乙個arp請求和應答(第7、8行)。

第9行表示rst被傳送出去。

客戶收到復位報文段後顯示連線已被另一端的主機終止(telnet客戶程式發出的最後資訊不再有什麼價值)。

TCP產生復位報文段RST的三種情況

在某些特殊情況下,tcp連線的一端會向另一端傳送攜帶rts標誌的報文段,即復位報文段,以通知對方關閉連線或重新建立連線。訪問不存在的埠 當客戶端程式訪問乙個不存在的埠時,目標主機將給他傳送乙個復位報文段。異常終止連線 tcp提供了異常終止連線的方法,即給對方傳送乙個復位報文段。一旦傳送了復位報文段,...

多執行緒和TCP網路連線

今天學習了多執行緒和tcp網路連線,彷彿開啟了一扇新的大門,很興奮。貼出部分 多執行緒 using system using system.collections.generic using system.linq using system.text using system.threading.t...

python網路連線之tcp通訊

encoding utf 8 建立乙個 tcp 伺服器程式,這個程式會把客戶傳送過來的字 符串加上乙個時間戳 格式 時間 資料 返回給客戶。from socket import from time import ctime host port 21567 bufsiz 1024 addr host,...