http://my.oschina.net/costaxu/blog/127394
在TCP協議中RST表示復位,用來異常的關閉連接,在TCP的設計中它是不可或缺的。發送RST包關閉連接時,不必等緩沖區的包都發出去,直接就丟棄緩存區的包發送RST包。而接收端收到RST包后,也不必發送ACK包來確認。
其實在網絡編程過程中,各種RST錯誤其實是比較難排查和找到原因的。下面我列出幾種會出現RST的情況。
1 端口未打開
服務器程序端口未打開而客戶端來連接。這種情況是最為常見和好理解的一種了。去telnet一個未打開的TCP的端口可能會出現這種錯誤。這個和操作系統的實現有關。在某些情況下,操作系統也會完全不理會這些發到未打開端口請求。
比如在下面這種情況下,主機241向主機114發送一個SYN請求,表示想要連接主機114的40000端口,但是主機114上根本沒有打開40000這個端口,於是就向主機241發送了一個RST。這種情況很常見。特別是服務器程序core dump之后重啟之前連續出現RST的情況會經常發生。
當然在某些操作系統的主機上,未必是這樣的表現。比如向一台WINDOWS7的主機發送一個連接不存在的端口的請求,這台主機就不會回應。
2 請求超時
曾經遇到過這樣一個情況:一個客戶端連接服務器,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拒絕進一步發送數據。
3 提前關閉
關於TCP,我想我們在教科書里都讀到過一句話,'TCP是一種可靠的連接'。 而這可靠有這樣一種含義,那就是操作系統接收到的來自TCP連接中的每一個字節,我都會讓應用程序接收到。如果應用程序不接收怎么辦?你猜對了,RST。
看兩段程序:
這一段是server的最簡單的代碼。邏輯很簡單,監聽一個TCP端口然后當有客戶端來連接的時候fork一個子進程來處理。注意看的是這一段fork里面的處理:
1
2
3
|
char
pcContent[4096];
read(real_fd,pcContent,4096);
close(real_fd);
|
每次只是讀socket的前4096個字節,然后就關閉掉連接。
然后再看一下client的代碼:
這段代碼更簡單,就是打開一個socket然后連接一個服務器並發送5000個字節。剛才我們看服務器的代碼,每次只接收4096個字節,那么就是說客戶端發送的剩下的4個字節服務端的應用程序沒有接收到,服務器端的socket就被關閉掉,這種情況下會發生什么狀況呢,還是抓包看一看。
前三行就是TCP的3次握手,從第四行開始看,客戶端的49660端口向服務器的9877端口發送了5000個字節的數據,然后服務器端發送了一個ACK進行了確認,緊接着服務器向客戶端發送了一個RST斷開了連接。和我們的預期一致。
客戶端在服務端已經關閉掉socket之后,仍然在發送數據。這時服務端會產生RST
1 從TCP協議的原理來談談RST攻擊 http://russelltao.iteye.com/blog/1405349
2 TCP客戶-服務器程序例子http://blog.csdn.net/youkuxiaobin/article/details/6917880