幾種TCP連線中出現RST的情況

2021-07-31 20:26:00 字數 3839 閱讀 4267

應該沒有人會質疑,現在是乙個網路時代了。應該不少程式設計師在程式設計中需要考慮多機、區域網、廣域網的各種問題。所以網路知識也是避免不了學習的。而且筆者一直覺得tcp/ip網路知識在乙個程式設計師知識體系中必需占有一席之地的。

在tcp協議中rst表示復位,用來異常的關閉連線,在tcp的設計中它是不可或缺的。傳送rst包關閉連線時,不必等緩衝區的包都發出去,直接就丟棄快取區的包傳送rst包。而接收端收到rst包後,也不必傳送ack包來確認。

其實在網路程式設計過程中,各種rst錯誤其實是比較難排查和找到原因的。下面我列出幾種會出現rst的情況。

伺服器程式埠未開啟而客戶端來連線。這種情況是最為常見和好理解的一種了。去telnet乙個未開啟的tcp的埠可能會出現這種錯誤。這個和作業系統的實現有關。在某些情況下,作業系統也會完全不理會這些發到未開啟埠請求。

比如在下面這種情況下,主機241向主機114傳送乙個syn請求,表示想要連線主機114的40000埠,但是主機114上根本沒有開啟40000這個埠,於是就向主機241傳送了乙個rst。這種情況很常見。特別是伺服器程式core dump之後重啟之前連續出現rst的情況會經常發生。

當然在某些作業系統的主機上,未必是這樣的表現。比如向一台windows7的主機傳送乙個連線不存在的埠的請求,這台主機就不會回應。

曾經遇到過這樣乙個情況:乙個客戶端連線伺服器,connect返回-1並且error=einprogress。 直接telnet發現網路連線沒有問題。ping沒有出現丟包。用抓包工具檢視,客戶端是在收到伺服器發出的syn之後就莫名其妙的傳送了rst。

比如像下面這樣:

有89、27兩台主機。主機89向主機27傳送了乙個syn,表示希望連線8888埠,主機27回應了主機89乙個syn表示可以連線。但是主機27卻很不友好,莫名其妙的傳送了乙個rst表示我不想連線你了。

後來經過排查發現,在主機89上的程式在建立了socket之後,用setsockopt的so_rcvtimeo選項設定了recv的超時時間為100ms。而我們看上面的抓包結果表示,從主機89發出syn到接收syn的時間多達110ms。(從15:01:27.799961到15:01:27.961886, 小數點之後的單位是微秒)。因此主機89上的程式認為接收超時,所以傳送了rst拒絕進一步傳送資料。

關於tcp,我想我們在教科書裡都讀到過一句話,'tcp是一種可靠的連線'。 而這可靠有這樣一種含義,那就是作業系統接收到的來自tcp連線中的每乙個位元組,我都會讓應用程式接收到。如果應用程式不接收怎麼辦?你猜對了,rst。

看兩段程式:

int main(int argc, char** argv)  

bzero(&listen_addr,sizeof(listen_addr));

listen_addr.sin_family = af_inet;

listen_addr.sin_addr.s_addr = htonl(inaddr_any);

listen_addr.sin_port = htons(serv_port);

bind(listen_fd,(struct sockaddr *)&listen_addr, len);

listen(listen_fd, wait_count);

while(1)

if(fork() == 0)

close(real_fd);

}

return 0;

}

這一段是server的最簡單的**。邏輯很簡單,監聽乙個tcp埠然後當有客戶端來連線的時候fork乙個子程序來處理。注意看的是這一段fork裡面的處理:

char pccontent[4096];

read(real_fd,pccontent,4096);

close(real_fd);

每次只是讀socket的前4096個位元組,然後就關閉掉連線。

然後再看一下client的**:

int main(int argc, char** argv)  

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = af_inet;

inet_pton(af_inet,ser_ip,&s_addr.sin_addr);

s_addr.sin_port = htons(ser_port);

if(connect(send_sk,(struct sockaddr*)&s_addr,len) == -1)

char pccontent[5000]=;

write(send_sk,pccontent,5000);

sleep(1);

close(send_sk);

}

這段**更簡單,就是開啟乙個socket然後連線乙個伺服器並傳送5000個位元組。剛才我們看伺服器的**,每次只接收4096個位元組,那麼就是說客戶端傳送的剩下的4個位元組服務端的應用程式沒有接收到,伺服器端的socket就被關閉掉,這種情況下會發生什麼狀況呢,還是抓包看一看。

如果某個socket已經關閉,但依然收到資料也會產生rst。

**如下:

客戶端:

int main(int argc, char** argv)  

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = af_inet;

inet_pton(af_inet,ser_ip,&s_addr.sin_addr);

s_addr.sin_port = htons(ser_port);

if(connect(send_sk,(struct sockaddr*)&s_addr,len) == -1)

char pccontent[4096]=;

write(send_sk,pccontent,4096);

sleep(1);

write(send_sk,pccontent,4096);

close(send_sk);

}

服務端:

int main(int argc, char** argv)  

bzero(&listen_addr,sizeof(listen_addr));

listen_addr.sin_family = af_inet;

listen_addr.sin_addr.s_addr = htonl(inaddr_any);

listen_addr.sin_port = htons(serv_port);

bind(listen_fd,(struct sockaddr *)&listen_addr, len);

listen(listen_fd, wait_count);

while(1)

if(fork() == 0)

close(real_fd);

}

return 0;

}

客戶端在服務端已經關閉掉socket之後,仍然在傳送資料。這時服務端會產生rst。

1 從tcp協議的原理來談談rst攻擊

2 tcp客戶-伺服器程式例子

幾種TCP連線中出現RST的情況

應該沒有人會質疑,現在是乙個網路時代了。應該不少程式設計師在程式設計中需要考慮多機 區域網 廣域網的各種問題。所以網路知識也是避免不了學習的。而且筆者一直覺得tcp ip網路知識在乙個程式設計師知識體系中必需占有一席之地的。在tcp協議中rst表示復位,用來異常的關閉連線,在tcp的設計中它是不可或...

幾種TCP連線中出現RST的情況

在tcp協議中rst表示復位,用來異常的關閉連線,在tcp的設計中它是不可或缺的。傳送rst包關閉連線時,不必等緩衝區的包都發出去,直接就丟棄快取區的包傳送rst包。而接收端收到rst包後,也不必傳送ack包來確認。其實在網路程式設計過程中,各種rst錯誤其實是比較難排查和找到原因的。下面列出幾種會...

tcp出現rst的情況

正常情況tcp四層握手關閉連線,rst基本都是異常情況,整理如下 1.gfw 2.對方埠未開啟,發生在連線建立 如果對方sync backlog滿了的話,sync簡單被丟棄,表現為超時,而不會rst 3.close socket 時recv buffer 不為空 例如,客戶端發了兩個請求,伺服器只從...