1、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)啃洋、netstat -nat? 查看TCP各個狀態(tài)的數(shù)量2)坞古、lsof? -i:port? 可以檢測到打開套接字的狀況3)、? sar -n SOCK 查看tcp創(chuàng)建的連接數(shù)4)辞居、tcpdump -iany tcp port 9000 對tcp端口為9000的進行抓包LISTENING:偵聽來自遠方的TCP端口的連接請求.? ? ? ? ? ? ? ? ? 首先服務端需要打開一個socket進行監(jiān)聽,狀態(tài)為LISTEN寨腔。? ? 有提供某種服務才會處于LISTENING狀態(tài)速侈,TCP狀態(tài)變化就是某個端口的狀態(tài)變化,提供一個服務就打開一個端口迫卢,例如:提供www服務默認開的是80端口倚搬,提供ftp服務默認的端口為21,當提供的服務沒有被連接時就處于LISTENING狀態(tài)乾蛤。FTP服務啟動后首先處于偵聽(LISTENING)狀態(tài)每界。處于偵聽LISTENING狀態(tài)時,該端口是開放的家卖,等待連接眨层,但還沒有被連接。就像你房子的門已經(jīng)敞開的上荡,但還沒有人進來趴樱。? ? 看LISTENING狀態(tài)最主要的是看本機開了哪些端口馒闷,這些端口都是哪個程序開的,關閉不必要的端口是保證安全的一個非常重要的方面叁征,服務端口都對應一個服務(應用程序)纳账,停止該服務就關閉了該端口,例如要關閉21端口只要停止IIS服務中的FTP服務即可捺疼。關于這方面的知識請參閱其它文章疏虫。? ? 如果你不幸中了服務端口的木馬,木馬也開個端口處于LISTENING狀態(tài)啤呼。SYN-SENT:客戶端SYN_SENT狀態(tài):? ? ? ? 再發(fā)送連接請求后等待匹配的連接請求:客戶端通過應用程序調用connect進行active open.于是客戶端tcp發(fā)送一個SYN以請求建立一個連接.之后狀態(tài)置為SYN_SENT. /*The socket is actively attempting to establish a connection. 在發(fā)送連接請求后等待匹配的連接請求 */? ? 當請求連接時客戶端首先要發(fā)送同步信號給要訪問的機器卧秘,此時狀態(tài)為SYN_SENT,如果連接成功了就變?yōu)镋STABLISHED官扣,正常情況下SYN_SENT狀態(tài)非常短暫翅敌。例如要訪問網(wǎng)站http://www.baidu.com,如果是正常連接的話,用TCPView觀察IEXPLORE.EXE(IE)建立的連接會發(fā)現(xiàn)很快從SYN_SENT變?yōu)镋STABLISHED惕蹄,表示連接成功哼御。SYN_SENT狀態(tài)快的也許看不到。? ? 如果發(fā)現(xiàn)有很多SYN_SENT出現(xiàn)焊唬,那一般有這么幾種情況,一是你要訪問的網(wǎng)站不存在或線路不好看靠,二是用掃描軟件掃描一個網(wǎng)段的機器赶促,也會出出現(xiàn)很多SYN_SENT,另外就是可能中了病毒了挟炬,例如中了"沖擊波"鸥滨,病毒發(fā)作時會掃描其它機器,這樣會有很多SYN_SENT出現(xiàn)谤祖。SYN-RECEIVED:服務器端狀態(tài)SYN_RCVD? ? ? ? ? 再收到和發(fā)送一個連接請求后等待對方對連接請求的確認? 當服務器收到客戶端發(fā)送的同步信號時婿滓,將標志位ACK和SYN置1發(fā)送給客戶端,此時服務器端處于SYN_RCVD狀態(tài)粥喜,如果連接成功了就變?yōu)镋STABLISHED凸主,正常情況下SYN_RCVD狀態(tài)非常短暫。? 如果發(fā)現(xiàn)有很多SYN_RCVD狀態(tài)额湘,那你的機器有可能被SYN Flood的DoS(拒絕服務攻擊)攻擊了卿吐。? SYN Flood的攻擊原理是:? 在進行三次握手時,攻擊軟件向被攻擊的服務器發(fā)送SYN連接請求(握手的第一步)锋华,但是這個地址是偽造的嗡官,如攻擊軟件隨機偽造了51.133.163.104、65.158.99.152等等地址毯焕。服務器在收到連接請求時將標志位ACK和SYN置1發(fā)送給客戶端(握手的第二步)衍腥,但是這些客戶端的IP地址都是偽造的,服務器根本找不到客戶機,也就是說握手的第三步不可能完成婆咸。? ? 這種情況下服務器端一般會重試(再次發(fā)送SYN+ACK給客戶端)并等待一段時間后丟棄這個未完成的連接竹捉,這段時間的長度我們稱為SYN Timeout,一般來說這個時間是分鐘的數(shù)量級(大約為30秒-2分鐘)擅耽;一個用戶出現(xiàn)異常導致服務器的一個線程等待1分鐘并不是什么很大的問題活孩,但如果有一個惡意的攻擊者大量模擬這種情況,服務器端將為了維護一個非常大的半連接列表而消耗非常多的資源----數(shù)以萬計的半連接乖仇,即使是簡單的保存并遍歷也會消耗非常多的CPU時間和內(nèi)存憾儒,何況還要不斷對這個列表中的IP進行SYN+ACK的重試。此時從正衬松常客戶的角度看來起趾,服務器失去響應,這種情況我們稱做:服務器端受到了SYN Flood攻擊(SYN洪水攻擊)ESTABLISHED:代表一個打開的連接警儒。? ? ESTABLISHED狀態(tài)是表示兩臺機器正在傳輸數(shù)據(jù)训裆,觀察這個狀態(tài)最主要的就是看哪個程序正在處于ESTABLISHED狀態(tài)。? ? 服務器出現(xiàn)很多ESTABLISHED狀態(tài): netstat -nat |grep 9502或者使用lsof? -i:9502可以檢測到蜀铲。? ? ? 當客戶端未主動close的時候就斷開連接:即客戶端發(fā)送的FIN丟失或未發(fā)送边琉。? ? ? ? 這時候若客戶端斷開的時候發(fā)送了FIN包,則服務端將會處于CLOSE_WAIT狀態(tài)记劝;? ? ? ? 這時候若客戶端斷開的時候未發(fā)送FIN包变姨,則服務端處還是顯示ESTABLISHED狀態(tài);? ? ? ? ? 結果客戶端重新連接服務器厌丑。? ? ? ? ? 而新連接上來的客戶端(也就是剛才斷掉的重新連上來了)在服務端肯定是ESTABLISHED; 如果客戶端重復的上演這種情況定欧,那么服務端將會出現(xiàn)大量的假的ESTABLISHED連接和CLOSE_WAIT連接。? ? ? ? 最終結果就是新的其他客戶端無法連接上來怒竿,但是利用netstat還是能看到一條連接已經(jīng)建立砍鸠,并顯示ESTABLISHED,但始終無法進入程序代碼耕驰。FIN-WAIT-1:等待遠程TCP連接中斷請求爷辱,或先前的連接中斷請求的確認? ? ? 主動關閉(active close)端應用程序調用close,于是其TCP發(fā)出FIN請求主動關閉連接朦肘,之后進入FIN_WAIT1狀態(tài)./* The socket is closed, and the connection is shutting down. 等待遠程TCP的連接中斷請求托嚣,或先前的連接中斷請求的確認 */? ? ? 如果服務器出現(xiàn)shutdown再重啟,使用netstat -nat查看厚骗,就會看到很多FIN-WAIT-1的狀態(tài)示启。就是因為服務器當前有很多客戶端連接,直接關閉服務器后领舰,無法接收到客戶端的ACK夫嗓。FIN-WAIT-2:從遠程TCP等待連接中斷請求? ? ? 主動關閉端接到ACK后迟螺,就進入了FIN-WAIT-2 ./* Connection is closed, and the socket is waiting for a shutdown from the remote end. 從遠程TCP等待連接中斷請求 */? ? ? ? 這就是著名的半關閉的狀態(tài)了,這是在關閉連接時舍咖,客戶端和服務器兩次握手之后的狀態(tài)矩父。在這個狀態(tài)下,應用程序還有接受數(shù)據(jù)的能力排霉,但是已經(jīng)無法發(fā)送數(shù)據(jù)窍株,但是也有一種可能是,客戶端一直處于FIN_WAIT_2狀態(tài)攻柠,而服務器則一直處于WAIT_CLOSE狀態(tài)球订,而直到應用層來決定關閉這個狀態(tài)。CLOSE-WAIT:等待從本地用戶發(fā)來的連接中斷請求? ? ? ? 被動關閉(passive close)端TCP接到FIN后瑰钮,就發(fā)出ACK以回應FIN請求(它的接收也作為文件結束符傳遞給上層應用程序),并進入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待從本地用戶發(fā)來的連接中斷請求 */? ? ? CLOSING:等待遠程TCP對連接中斷的確認比較少見./* Both sockets are shut down but we still don't have all our data sent. 等待遠程TCP對連接中斷的確認 */LAST-ACK:等待原來的發(fā)向遠程TCP的連接中斷請求的確認被動關閉端一段時間后冒滩,接收到文件結束符的應用程序將調用CLOSE關閉連接。這導致它的TCP也發(fā)送一個 FIN,等待對方的ACK.就進入了LAST-ACK . /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原來發(fā)向遠程TCP的連接中斷請求的確認 */使用并發(fā)壓力測試的時候浪谴,突然斷開壓力測試客戶端开睡,服務器會看到很多LAST-ACK。TIME-WAIT:等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認在主動關閉端接收到FIN后苟耻,TCP就發(fā)送ACK包篇恒,并進入TIME-WAIT狀態(tài)。/* The socket is waiting after close to handle packets still in the network.等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認 */? ? ? ? ? ? TIME_WAIT等待狀態(tài)凶杖,這個狀態(tài)又叫做2MSL狀態(tài)婚度,說的是在TIME_WAIT2發(fā)送了最后一個ACK數(shù)據(jù)報以后,要進入TIME_WAIT狀態(tài)官卡,這個狀態(tài)是防止最后一次握手的數(shù)據(jù)報沒有傳送到對方那里而準備的(注意這不是四次握手,這是第四次握手的保險狀態(tài))醋虏。這個狀態(tài)在很大程度上保證了雙方都可以正常結束寻咒,但是,問題也來了颈嚼。由于插口的2MSL狀態(tài)(插口是IP和端口對的意思毛秘,socket),使得應用程序在2MSL時間內(nèi)是無法再次使用同一個插口的阻课,對于客戶程序還好一些叫挟,但是對于服務程序,例如httpd限煞,它總是要使用同一個端口來進行服務抹恳,而在2MSL時間內(nèi),啟動httpd就會出現(xiàn)錯誤(插口被使用)署驻。為了避免這個錯誤奋献,服務器給出了一個平靜時間的概念健霹,這是說在2MSL時間內(nèi),雖然可以重新啟動服務器瓶蚂,但是這個服務器還是要平靜的等待2MSL時間的過去才能進行下一次連接糖埋。? ? ? ? ? ? ? ? ? 詳情請看:TIME_WAIT引起Cannot assign requested address報錯CLOSED:沒有任何連接狀態(tài)被動關閉端在接受到ACK包后,就進入了closed的狀態(tài)窃这。連接結束./* The socket is not being used. 沒有任何連接狀態(tài) */? ? ? ? 2瞳别、TCP狀態(tài)遷移路線圖client/server兩條路線講述TCP狀態(tài)遷移路線圖:? ? ? ? 這是一個看起來比較復雜的狀態(tài)遷移圖,因為它包含了兩個部分---服務器的狀態(tài)遷移和客戶端的狀態(tài)遷移杭攻,如果從某一個角度出發(fā)來看這個圖祟敛,就會清晰許多,這里面的服務器和客戶端都不是絕對的朴上,發(fā)送數(shù)據(jù)的就是客戶端垒棋,接受數(shù)據(jù)的就是服務器。 客戶端應用程序的狀態(tài)遷移圖? ? ? ? 客戶端的狀態(tài)可以用如下的流程來表示:? ? ? ? CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED? ? ? ? 以上流程是在程序正常的情況下應該有的流程痪宰,從書中的圖中可以看到叼架,在建立連接時,當客戶端收到SYN報文的ACK以后衣撬,客戶端就打開了數(shù)據(jù)交互地連接乖订。而結束連接則通常是客戶端主動結束的,客戶端結束應用程序以后具练,需要經(jīng)歷FIN_WAIT_1乍构,F(xiàn)IN_WAIT_2等狀態(tài),這些狀態(tài)的遷移就是前面提到的結束連接的四次握手扛点。 服務器的狀態(tài)遷移圖? ? ? ? 服務器的狀態(tài)可以用如下的流程來表示:? ? ? ? CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED? ? ? ? 在建立連接的時候哥遮,服務器端是在第三次握手之后才進入數(shù)據(jù)交互狀態(tài)盯捌,而關閉連接則是在關閉連接的第二次握手以后(注意不是第四次)镜悉。而關閉以后還要等待客戶端給出最后的ACK包才能進入初始的狀態(tài)。 其他狀態(tài)遷移還有一些其他的狀態(tài)遷移制跟,這些狀態(tài)遷移針對服務器和客戶端兩方面的總結如下LISTEN->SYN_SENT铜邮,對于這個解釋就很簡單了仪召,服務器有時候也要打開連接的嘛。SYN_SENT->SYN收到松蒜,服務器和客戶端在SYN_SENT狀態(tài)下如果收到SYN數(shù)據(jù)報扔茅,則都需要發(fā)送SYN的ACK數(shù)據(jù)報并把自己的狀態(tài)調整到SYN收到狀態(tài),準備進入ESTABLISHEDSYN_SENT->CLOSED秸苗,在發(fā)送超時的情況下召娜,會返回到CLOSED狀態(tài)。SYN_收到->LISTEN惊楼,如果受到RST包萤晴,會返回到LISTEN狀態(tài)吐句。SYN_收到->FIN_WAIT_1,這個遷移是說店读,可以不用到ESTABLISHED狀態(tài)嗦枢,而可以直接跳轉到FIN_WAIT_1狀態(tài)并等待關閉。? 怎樣牢牢地將這張圖刻在腦中呢屯断?那么你就一定要對這張圖的每一個狀態(tài)文虏,及轉換的過程有深刻的認識,不能只停留在一知半解之中殖演。下面對這張圖的11種狀態(tài)詳細解析一下氧秘,以便加強記憶!不過在這之前趴久,先回顧一下TCP建立連接的三次握手過程丸相,以及關閉連接的四次握手過程。3彼棍、TCP連接建立三次握手? ? TCP是一個面向連接的協(xié)議灭忠,所以在連接雙方發(fā)送數(shù)據(jù)之前,都需要首先建立一條連接座硕。? ? ? ? ? Client連接Server:? ? 當Client端調用socket函數(shù)調用時弛作,相當于Client端產(chǎn)生了一個處于Closed狀態(tài)的套接字。? ? ? ( 1)? 第一次握手:Client端又調用connect函數(shù)調用华匾,系統(tǒng)為Client隨機分配一個端口映琳,連同傳入connect中的參數(shù)(Server的IP和端口),這就形成了一個連接四元組蜘拉,客戶端發(fā)送一個帶SYN標志的TCP報文到服務器萨西。這是三次握手過程中的報文1。connect調用讓Client端的socket處于SYN_SENT狀態(tài)旭旭,等待服務器確認谎脯;SYN:同步序列編號(Synchronize Sequence Numbers)。? ? ? ( 2)第二次握手: 服務器收到syn包您机,必須確認客戶的SYN(ack=j+1),同時自己也發(fā)送一個SYN包(syn=k)年局,即SYN+ACK包际看,此時服務器進入SYN_RECV狀態(tài);? ? ? ( 3)? 第三次握手:客戶端收到服務器的SYN+ACK包矢否,向服務器發(fā)送確認包ACK(ack=k+1)仲闽,此包發(fā)送完畢,客戶器和客務器進入ESTABLISHED狀態(tài)僵朗,完成三次握手赖欣。連接已經(jīng)可以進行讀寫操作屑彻。一個完整的三次握手也就是: 請求---應答---再次確認。TCP協(xié)議通過三個報文段完成連接的建立顶吮,這個過程稱為三次握手(three-way handshake)社牲,過程如下圖所示。對應的函數(shù)接口:? ? ? ? ? 2)Server? ? 當Server端調用socket函數(shù)調用時悴了,相當于Server端產(chǎn)生了一個處于Closed狀態(tài)的監(jiān)聽套接字? ? ? Server端調用bind操作搏恤,將監(jiān)聽套接字與指定的地址和端口關聯(lián),然后又調用listen函數(shù)湃交,系統(tǒng)會為其分配未完成隊列和完成隊列熟空,此時的監(jiān)聽套接字可以接受Client的連接,監(jiān)聽套接字狀態(tài)處于LISTEN狀態(tài)搞莺。? ? 當Server端調用accept操作時息罗,會從完成隊列中取出一個已經(jīng)完成的client連接,同時在server這段會產(chǎn)生一個會話套接字才沧,用于和client端套接字的通信迈喉,這個會話套接字的狀態(tài)是ESTABLISH。從圖中可以看出糜工,當客戶端調用connect時弊添,觸發(fā)了連接請求,向服務器發(fā)送了SYN J包捌木,這時connect進入阻塞狀態(tài)油坝;服務器監(jiān)聽到連接請求,即收到SYN J包刨裆,調用accept函數(shù)接收請求向客戶端發(fā)送SYN K 澈圈,ACK J+1,這時accept進入阻塞狀態(tài)帆啃;客戶端收到服務器的SYN K 瞬女,ACK J+1之后,這時connect返回努潘,并對SYN K進行確認诽偷;服務器收到ACK K+1時,accept返回疯坤,至此三次握手完畢报慕,連接建立。我們可以通過網(wǎng)絡抓包的查看具體的流程:比如我們服務器開啟9502的端口压怠。使用tcpdump來抓包: tcpdump -iany tcp port 9502然后我們使用telnet 127.0.0.1 9502開連接.:telnet 127.0.0.1 950214:12:45.104687 IP localhost.39870 > localhost.9502: Flags [S], seq 2927179378, win 32792, options [mss 16396,sackOK,TS val 255474104 ecr 0,nop,wscale 3], length 0(1)14:12:45.104701 IP localhost.9502 > localhost.39870: Flags [S.], seq 1721825043, ack 2927179379, win 32768, options [mss 16396,sackOK,TS val 255474104 ecr 255474104,nop,wscale 3], length 0? (2)14:12:45.104711 IP localhost.39870 > localhost.9502: Flags [.], ack 1, win 4099, options [nop,nop,TS val 255474104 ecr 255474104], length 0? (3)14:13:01.415407 IP localhost.39870 > localhost.9502: Flags [P.], seq 1:8, ack 1, win 4099, options [nop,nop,TS val 255478182 ecr 255474104], length 714:13:01.415432 IP localhost.9502 > localhost.39870: Flags [.], ack 8, win 4096, options [nop,nop,TS val 255478182 ecr 255478182], length 014:13:01.415747 IP localhost.9502 > localhost.39870: Flags [P.], seq 1:19, ack 8, win 4096, options [nop,nop,TS val 255478182 ecr 255478182], length 1814:13:01.415757 IP localhost.39870 > localhost.9502: Flags [.], ack 19, win 4097, options [nop,nop,TS val 255478182 ecr 255478182], length 0我們看到 (1)(2)(3)三步是建立tcp:第一次握手:14:12:45.104687 IP localhost.39870 > localhost.9502: Flags [S], seq 2927179378客戶端IP localhost.39870 (客戶端的端口一般是自動分配的) 向服務器localhost.9502 發(fā)送syn包(syn=j)到服務器》syn的seq= 2927179378第二次握手:14:12:45.104701 IP localhost.9502 > localhost.39870: Flags [S.], seq 1721825043, ack 2927179379,服務器收到syn包眠冈,必須確認客戶的SYN(ack=j+1),同時自己也發(fā)送一個SYN包(syn=k)菌瘫,即SYN+ACK包SYN(ack=j+1)=ack 2927179379? ? 服務器主機SYN包(syn=seq 1721825043)第三次握手:14:12:45.104711 IP localhost.39870 > localhost.9502: Flags [.], ack 1,客戶端收到服務器的SYN+ACK包蜗顽,向服務器發(fā)送確認包ACK(ack=k+1)客戶端和服務器進入ESTABLISHED狀態(tài)后布卡,可以進行通信數(shù)據(jù)交互。此時和accept接口沒有關系雇盖,即使沒有accepte忿等,也進行3次握手完成。連接出現(xiàn)連接不上的問題刊懈,一般是網(wǎng)路出現(xiàn)問題或者網(wǎng)卡超負荷或者是連接數(shù)已經(jīng)滿啦这弧。紫色背景的部分:IP localhost.39870 > localhost.9502: Flags [P.], seq 1:8, ack 1, win 4099, options [nop,nop,TS val 255478182 ecr 255474104], length 7客戶端向服務器發(fā)送長度為7個字節(jié)的數(shù)據(jù),IP localhost.9502 > localhost.39870: Flags [.], ack 8, win 4096, options [nop,nop,TS val 255478182 ecr 255478182], length 0服務器向客戶確認已經(jīng)收到數(shù)據(jù) IP localhost.9502 > localhost.39870: Flags [P.], seq 1:19, ack 8, win 4096, options [nop,nop,TS val 255478182 ecr 255478182], length 18然后服務器同時向客戶端寫入數(shù)據(jù)虚汛。 IP localhost.39870 > localhost.9502: Flags [.], ack 19, win 4097, options [nop,nop,TS val 255478182 ecr 255478182], length 0客戶端向服務器確認已經(jīng)收到數(shù)據(jù)這個就是tcp可靠的連接匾浪,每次通信都需要對方來確認。4. TCP連接的終止(四次握手釋放) 由于TCP連接是全雙工的卷哩,因此每個方向都必須單獨進行關閉蛋辈。這原則是當一方完成它的數(shù)據(jù)發(fā)送任務后就能發(fā)送一個FIN來終止這個方向的連接。收到一個 FIN只意味著這一方向上沒有數(shù)據(jù)流動将谊,一個TCP連接在收到一個FIN后仍能發(fā)送數(shù)據(jù)冷溶。首先進行關閉的一方將執(zhí)行主動關閉,而另一方執(zhí)行被動關閉尊浓。? ? ? 建立一個連接需要三次握手逞频,而終止一個連接要經(jīng)過四次握手,這是由TCP的半關閉(half-close)造成的栋齿,如圖:(1)客戶端A發(fā)送一個FIN苗胀,用來關閉客戶A到服務器B的數(shù)據(jù)傳送(報文段4)。(2)服務器B收到這個FIN瓦堵,它發(fā)回一個ACK基协,確認序號為收到的序號加1(報文段5)。和SYN一樣菇用,一個FIN將占用一個序號澜驮。(3)服務器B關閉與客戶端A的連接,發(fā)送一個FIN給客戶端A(報文段6)惋鸥。(4)客戶端A發(fā)回ACK報文確認杂穷,并將確認序號設置為收到序號加1(報文段7)。對應函數(shù)接口如圖:調用過程如下:1)? 當client想要關閉它與server之間的連接卦绣。client(某個應用進程)首先調用close主動關閉連接耐量,這時TCP發(fā)送一個FIN M;client端處于FIN_WAIT1狀態(tài)迎卤。2)? 當server端接收到FIN M之后拴鸵,執(zhí)行被動關閉玷坠。對這個FIN進行確認蜗搔,返回給client ACK劲藐。當server端返回給client ACK后,client處于FIN_WAIT2狀態(tài)樟凄,server處于CLOSE_WAIT狀態(tài)聘芜。它的接收也作為文件結束符傳遞給應用進程,因為FIN的接收? ? 意味著應用進程在相應的連接上再也接收不到額外數(shù)據(jù)缝龄;3)? 一段時間之后汰现,當server端檢測到client端的關閉操作(read返回為0)。接收到文件結束符的server端調用close關閉它的socket叔壤。這導致server端的TCP也發(fā)送一個FIN N瞎饲;此時server的狀態(tài)為LAST_ACK。4)? 當client收到來自server的FIN后 炼绘。 client端的套接字處于TIME_WAIT狀態(tài)嗅战,它會向server端再發(fā)送一個ack確認,此時server端收到ack確認后俺亮,此套接字處于CLOSED狀態(tài)驮捍。這樣每個方向上都有一個FIN和ACK。1.為什么建立連接協(xié)議是三次握手脚曾,而關閉連接卻是四次握手呢东且?? ? ? ? 這是因為服務端的LISTEN狀態(tài)下的SOCKET當收到SYN報文的建連請求后,它可以把ACK和SYN(ACK起應答作用本讥,而SYN起同步作用)放在一個報文里來發(fā)送珊泳。但關閉連接時,當收到對方的FIN報文通知時囤踩,它僅僅表示對方?jīng)]有數(shù)據(jù)發(fā)送給你了旨椒;但未必你所有的數(shù)據(jù)都全部發(fā)送給對方了,所以你可以未必會馬上會關閉SOCKET,也即你可能還需要發(fā)送一些數(shù)據(jù)給對方之后堵漱,再發(fā)送FIN報文給對方來表示你同意現(xiàn)在可以關閉連接了综慎,所以它這里的ACK報文和FIN報文多數(shù)情況下都是分開發(fā)送的。2.為什么TIME_WAIT狀態(tài)還需要等2MSL后才能返回到CLOSED狀態(tài)勤庐?這是因為雖然雙方都同意關閉連接了示惊,而且握手的4個報文也都協(xié)調和發(fā)送完畢,按理可以直接回到CLOSED狀態(tài)(就好比從SYN_SEND狀態(tài)到ESTABLISH狀態(tài)那樣):一方面是可靠的實現(xiàn)TCP全雙工連接的終止愉镰,也就是當最后的ACK丟失后米罚,被動關閉端會重發(fā)FIN,因此主動關閉端需要維持狀態(tài)信息丈探,以允許它重新發(fā)送最終的ACK录择。另一方面,但是因為我們必須要假想網(wǎng)絡是不可靠的,你無法保證你最后發(fā)送的ACK報文會一定被對方收到隘竭,因此對方處于LAST_ACK狀態(tài)下的SOCKET可能會因為超時未收到ACK報文塘秦,而重發(fā)FIN報文,所以這個TIME_WAIT狀態(tài)的作用就是用來重發(fā)可能丟失的ACK報文动看。TCP在2MSL等待期間尊剔,定義這個連接(4元組)不能再使用,任何遲到的報文都會丟棄菱皆。設想如果沒有2MSL的限制须误,恰好新到的連接正好滿足原先的4元組,這時候連接就可能接收到網(wǎng)絡上的延遲報文就可能干擾最新建立的連接仇轻。5京痢、同時打開? ? ? ? 兩個應用程序同時執(zhí)行主動打開的情況是可能的,雖然發(fā)生的可能性較低篷店。每一端都發(fā)送一個SYN,并傳遞給對方历造,且每一端都使用對端所知的端口作為本地端口。例如:主機a中一應用程序使用7777作為本地端口船庇,并連接到主機b 8888端口做主動打開吭产。主機b中一應用程序使用8888作為本地端口,并連接到主機a 7777端口做主動打開鸭轮。tcp協(xié)議在遇到這種情況時臣淤,只會打開一條連接。這個連接的建立過程需要4次數(shù)據(jù)交換窃爷,而一個典型的連接建立只需要3次交換(即3次握手)但多數(shù)伯克利版的tcp/ip實現(xiàn)并不支持同時打開邑蒋。6、同時關閉如果應用程序同時發(fā)送FIN按厘,則在發(fā)送后會首先進入FIN_WAIT_1狀態(tài)医吊。在收到對端的FIN后,回復一個ACK逮京,會進入CLOSING狀態(tài)卿堂。在收到對端的ACK后,進入TIME_WAIT狀態(tài)懒棉。這種情況稱為同時關閉草描。同時關閉也需要有4次報文交換,與典型的關閉相同策严。 7. TCP通信中服務器處理客戶端意外斷開引用地址:http://blog.csdn.net/kkkkkxiaofei/article/details/12966407? ? ? 如果TCP連接被對方正常關閉穗慕,也就是說,對方是正確地調用了closesocket(s)或者shutdown(s)的話妻导,那么上面的Recv或Send調用就能馬上返回逛绵,并且報錯怀各。這是由于close socket(s)或者shutdown(s)有個正常的關閉過程,會告訴對方“TCP連接已經(jīng)關閉术浪,你不需要再發(fā)送或者接受消息了”渠啤。但是,如果意外斷開添吗,客戶端(3g的移動設備)并沒有正常關閉socket。雙方并未按照協(xié)議上的四次揮手去斷開連接份名。那么這時候正在執(zhí)行Recv或Send操作的一方就會因為沒有任何連接中斷的通知而一直等待下去碟联,也就是會被長時間卡住。? ? ? ? ? ? ? 像這種如果一方已經(jīng)關閉或異常終止連接僵腺,而另一方卻不知道鲤孵,我們將這樣的TCP連接稱為半打開的。? ? ? 解決意外中斷辦法都是利用背饺纾活機制普监。而保活機制分又可以讓底層實現(xiàn)也可自己實現(xiàn)琉兜。? ? 1凯正、自己編寫心跳包程序? ? 簡單的說也就是在自己的程序中加入一條線程,定時向對端發(fā)送數(shù)據(jù)包豌蟋,查看是否有ACK廊散,如果有則連接正常,沒有的話則連接斷開? ? 2梧疲、啟動TCP編程里的keepAlive機制一允睹、雙方擬定心跳(自實現(xiàn))? ? 一般由客戶端發(fā)送心跳包,服務端并不回應心跳幌氮,只是定時輪詢判斷一下與上次的時間間隔是否超時(超時時間自己設定)缭受。服務器并不主動發(fā)送是不想增添服務器的通信量,減少壓力该互。但這會出現(xiàn)三種情況:情況1.? ? ? 客戶端由于某種網(wǎng)絡延遲等原因很久后才發(fā)送心跳(它并沒有斷)米者,這時服務器若利用自身設定的超時判斷其已經(jīng)斷開,而后去關閉socket宇智。若客戶端有重連機制塘雳,則客戶端會重新連接。若不確定這種方式是否關閉了原本正常的客戶端普筹,則在ShutDown的時候一定要選擇send,表示關閉發(fā)送通道败明,服務器還可以接收一下,萬一客戶端正在發(fā)送比較重要的數(shù)據(jù)呢太防,是不妻顶?情況2.? ? ? 客戶端很久沒傳心跳酸员,確實是自身斷掉了。在其重啟之前讳嘱,服務端已經(jīng)判斷出其超時幔嗦,并主動close,則四次揮手成功交互沥潭。情況3.? ? ? 客戶端很久沒傳心跳邀泉,確實是自身斷掉了。在其重啟之前钝鸽,服務端的輪詢還未判斷出其超時汇恤,在未主動close的時候該客戶端已經(jīng)重新連接。? ? ? 這時候若客戶端斷開的時候發(fā)送了FIN包拔恰,則服務端將會處于CLOSE_WAIT狀態(tài)因谎;? ? ? 這時候若客戶端斷開的時候未發(fā)送FIN包,則服務端處還是顯示ESTABLISHED狀態(tài)颜懊;? ? ? 而新連接上來的客戶端(也就是剛才斷掉的重新連上來了)在服務端肯定是ESTABLISHED;這時候就有個問題财岔,若利用輪詢還未檢測出上條舊連接已經(jīng)超時(這很正常,timer總有個間隔吧)河爹,而在這時匠璧,客戶端又重復的上演情況3,那么服務端將會出現(xiàn)大量的假的ESTABLISHED連接和CLOSE_WAIT連接咸这。? ? ? ? 最終結果就是新的其他客戶端無法連接上來患朱,但是利用netstat還是能看到一條連接已經(jīng)建立,并顯示ESTABLISHED炊苫,但始終無法進入程序代碼裁厅。個人最初感覺導致這種情況是因為假的ESTABLISHED連接和CLOSE_WAIT連接會占用較大的系統(tǒng)資源,程序無法再次創(chuàng)建連接(因為每次我發(fā)現(xiàn)這個問題的時候我只連了10個左右客戶端卻已經(jīng)有40多條無效連接)侨艾。而最近幾天測試卻發(fā)現(xiàn)有一次程序內(nèi)只連接了2执虹,3個設備,但是有8條左右的虛連接唠梨,此時已經(jīng)連接不了新客戶端了袋励。這時候我就覺得我想錯了,不可能這幾條連接就占用了大量連接把当叭,如果說幾十條還有可能茬故。但是能肯定的是,這個問題的產(chǎn)生絕對是設備在不停的重啟蚁鳖,而服務器這邊又是簡單的輪詢磺芭,并不能及時處理,暫時還未能解決醉箕。二钾腺、利用KeepAlive? ? ? ? ? 其實keepalive的原理就是TCP內(nèi)嵌的一個心跳包,? ? ? ? 以服務器端為例徙垫,如果當前server端檢測到超過一定時間(默認是 7,200,000 milliseconds,也就是2個小時)沒有數(shù)據(jù)傳輸放棒,那么會向client端發(fā)送一個keep-alive packet(該keep-alive packet就是ACK和當前TCP序列號減一的組合)姻报,此時client端應該為以下三種情況之一:? ? ? ? 1. client端仍然存在,網(wǎng)絡連接狀況良好间螟。此時client端會返回一個ACK吴旋。server端接收到ACK后重置計時器(復位存活定時器),在2小時后再發(fā)送探測厢破。如果2小時內(nèi)連接上有數(shù)據(jù)傳輸荣瑟,那么在該時間基礎上向后推延2個小時。? ? ? ? 2. 客戶端異常關閉溉奕,或是網(wǎng)絡斷開。在這兩種情況下忍啤,client端都不會響應加勤。服務器沒有收到對其發(fā)出探測的響應,并且在一定時間(系統(tǒng)默認為1000 ms)后重復發(fā)送keep-alive packet同波,并且重復發(fā)送一定次數(shù)(2000 XP 2003 系統(tǒng)默認為5次, Vista后的系統(tǒng)默認為10次)鳄梅。? ? ? ? 3. 客戶端曾經(jīng)崩潰,但已經(jīng)重啟未檩。這種情況下戴尸,服務器將會收到對其存活探測的響應,但該響應是一個復位冤狡,從而引起服務器對連接的終止孙蒙。? ? ? 對于應用程序來說,2小時的空閑時間太長悲雳。因此挎峦,我們需要手工開啟Keepalive功能并設置合理的Keepalive參數(shù)。全局設置可更改/etc/sysctl.conf,加上:net.ipv4.tcp_keepalive_intvl = 20net.ipv4.tcp_keepalive_probes = 3net.ipv4.tcp_keepalive_time = 60在程序中設置如下:[cpp] view plain copy print?在CODE上查看代碼片派生到我的代碼片#include#include#include#include#includeint keepAlive = 1; // 開啟keepalive屬性
int keepIdle = 60; // 如該連接在60秒內(nèi)沒有任何數(shù)據(jù)往來,則進行探測
int keepInterval = 5; // 探測時發(fā)包的時間間隔為5 秒
int keepCount = 3; // 探測嘗試的次數(shù).如果第1次探測包就收到響應了,則后2次的不再發(fā).
setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
在程序中表現(xiàn)為,當tcp檢測到對端socket不再可用時(不能發(fā)出探測包,或探測包沒有收到ACK的響應包),select會返回socket可讀,并且在recv時返回-1,同時置上errno為ETIMEDOUT.
8. Linux錯誤信息(errno)列表
經(jīng)常出現(xiàn)的錯誤:
22:參數(shù)錯誤合瓢,比如ip地址不合法坦胶,沒有目標端口等
101:網(wǎng)絡不可達,比如不能ping通
111:鏈接被拒絕晴楔,比如目標關閉鏈接等
115:當鏈接設置為非阻塞時顿苇,目標沒有及時應答,返回此錯誤税弃,socket可以繼續(xù)使用纪岁。比如socket連接
附錄:Linux的錯誤碼表(errno table)
_ 124 EMEDIUMTYPE_ Wrong medium type
_ 123 ENOMEDIUM__ No medium found
_ 122 EDQUOT___? Disk quota exceeded
_ 121 EREMOTEIO__ Remote I/O error
_ 120 EISNAM___? Is a named type file
_ 119 ENAVAIL___ No XENIX semaphores available
_ 118 ENOTNAM___ Not a XENIX named type file
_ 117 EUCLEAN___ Structure needs cleaning
_ 116 ESTALE___? Stale NFS file handle
_ 115 EINPROGRESS? +Operation now in progress
操作正在進行中。一個阻塞的操作正在執(zhí)行则果。
_ 114 EALREADY__? Operation already in progress
_ 113 EHOSTUNREACH? No route to host
_ 112 EHOSTDOWN__ Host is down
_ 111 ECONNREFUSED? Connection refused
1蜂科、拒絕連接顽决。一般發(fā)生在連接建立時。
拔服務器端網(wǎng)線測試导匣,客戶端設置keep alive時才菠,recv較快返回0, 先收到ECONNREFUSED (Connection refused)錯誤碼贡定,其后都是ETIMEOUT赋访。
2、an error returned from connect(), so it can only occur in a client (if a client is defined as the party that initiates the connection
_ 110 ETIMEDOUT_? +Connection timed out
_ 109 ETOOMANYREFS? Too many references: cannot splice
_ 108 ESHUTDOWN__ Cannot send after transport endpoint shutdown
_ 107 ENOTCONN__? Transport endpoint is not connected
在一個沒有建立連接的socket上缓待,進行read蚓耽,write操作會返回這個錯誤。出錯的原因是socket沒有標識地址旋炒。Setsoc也可能會出錯步悠。
還有一種情況就是收到對方發(fā)送過來的RST包,系統(tǒng)已經(jīng)確認連接被斷開了。
_ 106 EISCONN___ Transport endpoint is already connected
一般是socket客戶端已經(jīng)連接了瘫镇,但是調用connect鼎兽,會引起這個錯誤。
_ 105 ENOBUFS___ No buffer space available
_ 104 ECONNRESET_? Connection reset by peer
連接被遠程主機關閉铣除。有以下幾種原因:遠程主機停止服務谚咬,重新啟動;當在執(zhí)行某些操作時遇到失敗,因為設置了“keep alive”選項尚粘,連接被關閉择卦,一般與ENETRESET一起出現(xiàn)。
1郎嫁、在客戶端服務器程序中秉继,客戶端異常退出,并沒有回收關閉相關的資源泽铛,服務器端會先收到ECONNRESET錯誤秕噪,然后收到EPIPE錯誤。
2厚宰、連接被遠程主機關閉腌巾。有以下幾種原因:遠程主機停止服務,重新啟動;當在執(zhí)行某些操作時遇到失敗铲觉,因為設置了“keep alive”選項澈蝙,連接被關閉,一般與ENETRESET一起出現(xiàn)撵幽。
3灯荧、遠程端執(zhí)行了一個“hard”或者“abortive”的關閉泡态。應用程序應該關閉socket甥材,因為它不再可用。當執(zhí)行在一個UDP socket上時,這個錯誤表明前一個send操作返回一個ICMP“port unreachable”信息馋记。
4跨晴、如果client關閉連接,server端的select并不出錯(不返回-1,使用select對唯一一個socket進行non- blocking檢測),但是寫該socket就會出錯,用的是send.錯誤號:ECONNRESET.讀(recv)socket并沒有返回錯誤兼犯。
5乳规、該錯誤被描述為“connection reset by peer”,即“對方復位連接”擦秽,這種情況一般發(fā)生在服務進程較客戶進程提前終止码荔。當服務進程終止時會向客戶 TCP 發(fā)送 FIN 分節(jié),客戶 TCP 回應 ACK感挥,服務 TCP 將轉入 FIN_WAIT2 狀態(tài)缩搅。此時如果客戶進程沒有處理該 FIN (如阻塞在其它調用上而沒有關閉 Socket 時),則客戶 TCP 將處于 CLOSE_WAIT 狀態(tài)触幼。當客戶進程再次向 FIN_WAIT2 狀態(tài)的服務 TCP 發(fā)送數(shù)據(jù)時硼瓣,則服務 TCP 將立刻響應 RST。一般來說置谦,這種情況還可以會引發(fā)另外的應用程序異常堂鲤,客戶進程在發(fā)送完數(shù)據(jù)后,往往會等待從網(wǎng)絡IO接收數(shù)據(jù)霉祸,很典型的如 read 或 readline 調用筑累,此時由于執(zhí)行時序的原因袱蜡,如果該調用發(fā)生在 RST 分節(jié)收到前執(zhí)行的話丝蹭,那么結果是客戶進程會得到一個非預期的 EOF 錯誤。此時一般會輸出“server terminated prematurely”-“服務器過早終止”錯誤坪蚁。
_ 103 ECONNABORTED? Software caused connection abort
1奔穿、軟件導致的連接取消。一個已經(jīng)建立的連接被host方的軟件取消敏晤,原因可能是數(shù)據(jù)傳輸超時或者是協(xié)議錯誤贱田。
2、該錯誤被描述為“software caused connection abort”嘴脾,即“軟件引起的連接中止”男摧。原因在于當服務和客戶進程在完成用于 TCP 連接的“三次握手”后,客戶 TCP 卻發(fā)送了一個 RST (復位)分節(jié)译打,在服務進程看來耗拓,就在該連接已由 TCP 排隊,等著服務進程調用 accept 的時候 RST 卻到達了奏司。POSIX 規(guī)定此時的 errno 值必須 ECONNABORTED乔询。源自 Berkeley 的實現(xiàn)完全在內(nèi)核中處理中止的連接,服務進程將永遠不知道該中止的發(fā)生韵洋。服務器進程一般可以忽略該錯誤竿刁,直接再次調用accept黄锤。
當TCP協(xié)議接收到RST數(shù)據(jù)段,表示連接出現(xiàn)了某種錯誤食拜,函數(shù)read將以錯誤返回鸵熟,錯誤類型為ECONNERESET。并且以后所有在這個套接字上的讀操作均返回錯誤监婶。錯誤返回時返回值小于0旅赢。
_ 102 ENETRESET__ Network dropped connection on reset
網(wǎng)絡重置時丟失連接。
由于設置了"keep-alive"選項惑惶,探測到一個錯誤煮盼,連接被中斷。在一個已經(jīng)失敗的連接上試圖使用setsockopt操作带污,也會返回這個錯誤僵控。
_ 101 ENETUNREACH_ Network is unreachable
網(wǎng)絡不可達。Socket試圖操作一個不可達的網(wǎng)絡鱼冀。這意味著local的軟件知道沒有路由到達遠程的host报破。
_ 100 ENETDOWN__? Network is down
_? 99 EADDRNOTAVAIL Cannot assign requested address
_? 98 EADDRINUSE_? Address already in use
_? 97 EAFNOSUPPORT? Address family not supported by protocol
_? 96 EPFNOSUPPORT? Protocol family not supported
_? 95 EOPNOTSUPP_? Operation not supported
_? 94 ESOCKTNOSUPPORT Socket type not supported
Socket類型不支持。指定的socket類型在其address family中不支持千绪。如可選選中選項SOCK_RAW充易,但實現(xiàn)并不支持SOCK_RAW sockets。
_? 93 EPROTONOSUPPORT Protocol not supported
不支持的協(xié)議荸型。系統(tǒng)中沒有安裝標識的協(xié)議盹靴,或者是沒有實現(xiàn)。如函數(shù)需要SOCK_DGRAM socket瑞妇,但是標識了stream protocol.稿静。
_? 92 ENOPROTOOPT_ Protocol not available
該錯誤不是一個 Socket 連接相關的錯誤。errno 給出該值可能由于辕狰,通過 getsockopt 系統(tǒng)調用來獲得一個套接字的當前選項狀態(tài)時改备,如果發(fā)現(xiàn)了系統(tǒng)不支持的選項參數(shù)就會引發(fā)該錯誤。
_? 91 EPROTOTYPE_? Protocol wrong type for socket
協(xié)議類型錯誤蔓倍。標識了協(xié)議的Socket函數(shù)在不支持的socket上進行操作悬钳。如ARPA Internet
UDP協(xié)議不能被標識為SOCK_STREAM socket類型。
_? 90 EMSGSIZE__ +Message too long
消息體太長偶翅。
發(fā)送到socket上的一個數(shù)據(jù)包大小比內(nèi)部的消息緩沖區(qū)大默勾,或者超過別的網(wǎng)絡限制,或是用來接收數(shù)據(jù)包的緩沖區(qū)比數(shù)據(jù)包本身小倒堕。
_? 89 EDESTADDRREQ? Destination address required
需要提供目的地址灾测。
在一個socket上的操作需要提供地址。如往一個ADDR_ANY 地址上進行sendto操作會返回這個錯誤。
_? 88 ENOTSOCK__? Socket operation on non-socket
在非socket上執(zhí)行socket操作媳搪。
_? 87 EUSERS___? Too many users
_? 86 ESTRPIPE__? Streams pipe error
_? 85 ERESTART__? Interrupted system call should be restarted
_? 84 EILSEQ___? Invalid or incomplete multibyte or wide character
_? 83 ELIBEXEC__? Cannot exec a shared library directly
_? 82 ELIBMAX___ Attempting to link in too many shared libraries
_? 81 ELIBSCN___ .lib section in a.out corrupted
_? 80 ELIBBAD___ Accessing a corrupted shared library
_? 79 ELIBACC___ Can not access a needed shared library
_? 78 EREMCHG___ Remote address changed
_? 77 EBADFD___? File descriptor in bad state
_? 76 ENOTUNIQ__? Name not unique on network
_? 75 EOVERFLOW__ Value too large for defined data type
_? 74 EBADMSG__? +Bad message
_? 73 EDOTDOT___ RFS specific error
_? 72 EMULTIHOP__ Multihop attempted
_? 71 EPROTO___? Protocol error
_? 70 ECOMM____ Communication error on send
_? 69 ESRMNT___? Srmount error
_? 68 EADV____? Advertise error
_? 67 ENOLINK___ Link has been severed
_? 66 EREMOTE___ Object is remote
_? 65 ENOPKG___? Package not installed
_? 64 ENONET___? Machine is not on the network
_? 63 ENOSR____ Out of streams resources
_? 62 ETIME____ Timer expired
_? 61 ENODATA___ No data available
_? 60 ENOSTR___? Device not a stream
_? 59 EBFONT___? Bad font file format
_? 57 EBADSLT___ Invalid slot
_? 56 EBADRQC___ Invalid request code
_? 55 ENOANO___? No anode
_? 54 EXFULL___? Exchange full
_? 53 EBADR____ Invalid request descriptor
_? 52 EBADE____ Invalid exchange
_? 51 EL2HLT___? Level 2 halted
_? 50 ENOCSI___? No CSI structure available
_? 49 EUNATCH___ Protocol driver not attached
_? 48 ELNRNG___? Link number out of range
_? 47 EL3RST___? Level 3 reset
_? 46 EL3HLT___? Level 3 halted
_? 45 EL2NSYNC__? Level 2 not synchronized
_? 44 ECHRNG___? Channel number out of range
_? 43 EIDRM____ Identifier removed
_? 42 ENOMSG___? No message of desired type
_? 40 ELOOP____ Too many levels of symbolic links
_? 39 ENOTEMPTY_? +Directory not empty
_? 38 ENOSYS___ +Function not implemented
_? 37 ENOLCK___ +No locks available
_? 36 ENAMETOOLONG +File name too long
_? 35 EDEADLK__? +Resource deadlock avoided
_? 34 ERANGE___ +Numerical result out of range
_? 33 EDOM____ +Numerical argument out of domain
_? 32 EPIPE___? +Broken pipe
接收端關閉(緩沖中沒有多余的數(shù)據(jù)),但是發(fā)送端還在write:
1铭段、Socket 關閉,但是socket號并沒有置-1秦爆。繼續(xù)在此socket上進行send和recv序愚,就會返回這種錯誤。這個錯誤會引發(fā)SIGPIPE信號等限,系統(tǒng)會將產(chǎn)生此EPIPE錯誤的進程殺死爸吮。所以,一般在網(wǎng)絡程序中望门,首先屏蔽此消息形娇,以免發(fā)生不及時設置socket進程被殺死的情況。
2筹误、write(..) on a socket that has been closed at the other end will cause a SIGPIPE.
3桐早、錯誤被描述為“broken pipe”,即“管道破裂”厨剪,這種情況一般發(fā)生在客戶進程不理會(或未及時處理)Socket 錯誤哄酝,繼續(xù)向服務 TCP 寫入更多數(shù)據(jù)時,內(nèi)核將向客戶進程發(fā)送 SIGPIPE 信號祷膳,該信號默認會使進程終止(此時該前臺進程未進行 core dump)陶衅。結合上邊的 ECONNRESET 錯誤可知,向一個 FIN_WAIT2 狀態(tài)的服務 TCP(已 ACK 響應 FIN 分節(jié))寫入數(shù)據(jù)不成問題直晨,但是寫一個已接收了 RST 的 Socket 則是一個錯誤搀军。
_? 31 EMLINK___ +Too many links
_? 30 EROFS___? +Read-only file system
_? 29 ESPIPE___ +Illegal seek
_? 28 ENOSPC___ +No space left on device
_? 27 EFBIG___? +File too large
_? 26 ETXTBSY___ Text file busy
_? 25 ENOTTY___ +Inappropriate ioctl for device
_? 24 EMFILE___ +Too many open files
打開了太多的socket。對進程或者線程而言抡秆,每種實現(xiàn)方法都有一個最大的可用socket數(shù)目處理奕巍,或者是全局的吟策,或者是局部的儒士。
_? 23 ENFILE___ +Too many open files in system
_? 22 EINVAL___ +Invalid argument
無效參數(shù)。提供的參數(shù)非法檩坚。有時也會與socket的當前狀態(tài)相關着撩,如一個socket并沒有進入listening狀態(tài),此時調用accept匾委,就會產(chǎn)生EINVAL錯誤拖叙。
_? 21 EISDIR___ +Is a directory
_? 20 ENOTDIR__? +Not a directory
_? 19 ENODEV___ +No such device
_? 18 EXDEV___? +Invalid cross-device link
_? 17 EEXIST___ +File exists
_? 16 EBUSY___? +Device or resource busy
_? 15 ENOTBLK___ Block device required
_? 14 EFAULT___ +Bad address地址錯誤
_? 13 EACCES___ +Permission denied
_? 12 ENOMEM___ +Cannot allocate memory
_? 11 EAGAIN___ +Resource temporarily unavailable
在讀數(shù)據(jù)的時候,沒有數(shù)據(jù)在底層緩沖的時候會遇到,一般的處理是循環(huán)進行讀操作,異步模式還會等待讀事件的發(fā)生再讀
1、Send返回值小于要發(fā)送的數(shù)據(jù)數(shù)目赂乐,會返回EAGAIN和EINTR薯鳍。
2、recv 返回值小于請求的長度時說明緩沖區(qū)已經(jīng)沒有可讀數(shù)據(jù)挨措,但再讀不一定會觸發(fā)EAGAIN挖滤,有可能返回0表示TCP連接已被關閉崩溪。
3、當socket是非阻塞時,如返回此錯誤,表示寫緩沖隊列已滿,可以做延時后再重試.
4斩松、在Linux進行非阻塞的socket接收數(shù)據(jù)時經(jīng)常出現(xiàn)Resource temporarily unavailable伶唯,errno代碼為11(EAGAIN),表明在非阻塞模式下調用了阻塞操作惧盹,在該操作沒有完成就返回這個錯誤乳幸,這個錯誤不會破壞socket的同步,不用管它钧椰,下次循環(huán)接著recv就可以粹断。對非阻塞socket而言,EAGAIN不是一種錯誤嫡霞。
_? 10 ECHILD___ +No child processes
__ 9 EBADF___? +Bad file descriptor
__ 8 ENOEXEC__? +Exec format error
__ 7 E2BIG___? +Argument list too long
__ 6 ENXIO___? +No such device or address
__ 5 EIO____? +Input/output error
__ 4 EINTR___? +Interrupted system call
阻塞的操作被取消阻塞的調用打斷姿染。如設置了發(fā)送接收超時,就會遇到這種錯誤秒际。
只能針對阻塞模式的socket悬赏。讀,寫阻塞的socket時娄徊,-1返回闽颇,錯誤號為INTR。另外寄锐,如果出現(xiàn)EINTR即errno為4兵多,錯誤描述Interrupted system call,操作也應該繼續(xù)橄仆。如果recv的返回值為0剩膘,那表明連接已經(jīng)斷開,接收操作也應該結束盆顾。
__ 3 ESRCH___? +No such process
__ 2 ENOENT___ +No such file or directory
__ 1 EPERM___? +Operation not permitted