導航:首頁 > 配伺服器 > 伺服器tcp怎麼保活

伺服器tcp怎麼保活

發布時間:2022-10-09 20:39:24

Ⅰ tcp協議依靠什麼使釋放連接過程得到保障

我忘記了在哪裡說過會出現3次揮手的TCP協議的連接是全雙工連接,一個TCP連接存在雙向的讀寫通道。 簡單說來是 「先關讀,後關寫」,一共需要四個階段。以客戶機發起關閉連接為例:1.伺服器讀通道關閉2.客戶機寫通道關閉3.客戶機讀通道關閉4.伺服器寫通道關閉關閉行為是在發起方數據發送完畢之後,給對方發出一個FIN(finish)數據段。直到接收到對方發送的FIN,且對方收到了接收確認ACK之後,雙方的數據通信完全結束,過程中每次接收都需要返回確認數據段ACK。詳細過程: 第一階段 客戶機發送完數據之後,向伺服器發送一個FIN數據段,序列號為i; 1.伺服器收到FIN(i)後,返回確認段ACK,序列號為i+1,關閉伺服器讀通道; 2.客戶機收到ACK(i+1)後,關閉客戶機寫通道; (此時,客戶機仍能通過讀通道讀取伺服器的數據,伺服器仍能通過寫通道寫數據) 第二階段 伺服器發送完數據之後,向客戶機發送一個FIN數據段,序列號為j; 3.客戶機收到FIN(j)後,返回確認段ACK,序列號為j+1,關閉客戶機讀通道; 4.伺服器收到ACK(j+1)後,關閉伺服器寫通道。這是標準的TCP關閉兩個階段,伺服器和客戶機都可以發起關閉,完全對稱。FIN標識是通過發送最後一塊數據時設置的,標準的例子中,伺服器還在發送數據,所以要等到發送完的時候,設置FIN(此時可稱為TCP連接處於半關閉狀態,因為數據仍可從被動關閉一方向主動關閉方傳送)。如果在伺服器收到FIN(i)時,已經沒有數據需要發送,可以在返回ACK(i+1)的時候就設置FIN(j)標識,這樣就相當於可以合並第二步和第三步。復制粘貼

Ⅱ TCP協議解析

主要特點:面向連接、面向位元組流、全雙工通信、通信可靠。

優缺點:

應用場景:要求通信數據可靠時,即 數據要准確無誤地傳遞給對方。如:傳輸文件:HTTP、HTTPS、FTP等協議;傳輸郵件:POP、SMTP等協議

ps:首部的前 20 個位元組固定,後面有 4n 位元組根據需要增加。故 TCP首部最小長度 = 20位元組(最大60個位元組)。

TCP報頭中的源埠號和目的埠號同IP數據報中的源IP與目的IP唯一確定一條TCP連接。

重要欄位:

客戶端與伺服器來回共發送三個TCP報文段來建立運輸連接,三個TCP報文段分別為:
(1)客戶端A向伺服器B發送的TCP請求報段「SYN=1,seq=x」;
(2)伺服器B向客戶端A發送的TCP確認報文段「SYN=1,ACK=1,seq=y,ack=x+1」;
(3)客戶端A向伺服器B發送的TCP確認報文段「ACK=1,seq=x+1,ack=y+1」。

ps:在建立TCP連接之前,客戶端和伺服器都處於關閉狀態(CLOSED),直到客戶端主動打開連接,伺服器才被動打開連接(處於監聽狀態 = LISTEN),等待客戶端的請求。

TCP 協議是一個面向連接的、安全可靠的傳輸層協議,三次握手的機制是為了保證能建立一個安全可靠的連接。

通過上述三次握手, 雙方確認自己與對方的發送與接收是正常的,就建立起一條TCP連接,即可傳送應用層數據 。ps:因 TCP提供的是全雙工通信,故通信雙方的應用進程在任何時候都能發送數據;三次握手期間,任何1次未收到對面的回復,則都會重發。

為什麼兩次握手不行呢

結論:防止伺服器接收了 早已經失效的連接請求報文 ,伺服器同意連接,從而一直等待客戶端請求, 最終導致形成死鎖、浪費資源

ps:SYN洪泛攻擊:(具體見下文)

為什麼不需要四次握手呢

SYN 同步序列編號(Synchronize Sequence Numbers) 是 TCP/IP 建立連接時使用的握手信號。在客戶機和伺服器之間建立正常的 TCP 網路連接時,客戶機首先發出一個 SYN 消息,伺服器使用 SYN-ACK 應答表示接收到了這個消息,最後客戶機再以 ACK確認序號標志消息響應。這樣在客戶機和伺服器之間才能建立起可靠的 TCP 連接,數據才可以在客戶機和伺服器之間傳遞。

如何來解決半連接攻擊?

如何來解決全連接攻擊?

請注意 ,現在 TCP 連接還沒有釋放掉。必須經過 時間等待計時器 設置的時間 2MSL(MSL:最長報文段壽命)後,客戶端才能進入到 CLOSED 狀態,然後撤銷傳輸控制塊,結束這次 TCP 連接。當然如果伺服器一收到 客戶端的確認就進入 CLOSED 狀態,然後撤銷傳輸控制塊。所以在釋放連接時,伺服器結束 TCP 連接的時間要早於客戶端。

TCP是全雙工的連接,必須兩端同時關閉連接,連接才算真正關閉。 簡言之,客戶端發送了 FIN 連接釋放報文之後,伺服器收到了這個報文,就進入了 CLOSE-WAIT 狀態。這個狀態是為了讓伺服器端發送還未傳送完畢的數據,傳送完畢之後,伺服器才會發送 FIN 連接釋放報文,對方確認後就完全關閉了TCP連接。

舉個例子:A 和 B 打電話,通話即將結束後,A 說「我沒啥要說的了」,B回答「我知道了」,但是 B 可能還會有要說的話,A 不能要求 B 跟著自己的節奏結束通話,於是 B 可能又巴拉巴拉說了一通,最後 B 說「我說完了」,A 回答「知道了」,這樣通話才算結束。

ps:設想這樣一個情景: 客戶端已主動與伺服器建立了 TCP 連接。但後來客戶端的主機突然發生故障。 顯然,伺服器以後就不能再收到客戶端發來的數據。因此,應當有措施使伺服器不要再白白等待下去。這就需要使用 TCP的保活計時器 。基本原理:

tcp11種狀態及變遷其實基本包含在正常的三次握手和四次揮手中,除開CLOSING。

正常的三次握手包括4中狀態變遷:

伺服器打開監聽(LISTEN)->客戶端先發起SYN主動連接標識->伺服器回復SYN及ACK確認->客戶端再確認即三次握手TCP連接成功。這里邊涉及四種狀態及變遷:

正常的四次握手包含6種tcp狀態變遷,如主動發起關閉方為客戶端:

客戶端發送FIN進入FIN_WAIT1 -> 伺服器發送ACK確認並進入CLOSE_WAIT(被動關閉)狀態->客戶端收到ACK確認後進入FIN_WAIT2狀態 -> 伺服器再發送FIN進入LAST_ACK狀態 -> 客戶端收到伺服器的FIN後發送ACK確認進入TIME_WAIT狀態 -> 伺服器收到ACK確認後進入CLOSED狀態斷開連接 -> 客戶端在等待2MSL的時間如果期間沒有收到伺服器的相關包,則進入CLOSED狀態斷開連接。

CLOSING狀態 :連接斷開期間,一般是客戶端發送一個FIN,然後伺服器回復一個ACK,然後伺服器發送完數據後再回復一個FIN,當客戶端和伺服器同時接受到FIN時,客戶端和伺服器處於CLOSING狀態,也就是此時雙方都正在關閉同一個連接。

在進入CLOSING狀態後,只要收到了對方對自己發送的FIN的ACK,收到FIN的ACK確認就進入TIME_WAIT狀態,因此,如果RTT(Round Trip Time TCP包的往返延時)處在一個可接受的范圍內,發出的FIN會很快被ACK從而進入到TIME_WAIT狀態,CLOSING狀態持續的時間就特別短,因此很難看到這種狀態。

我們知道網路層,可以實現兩個主機之間的通信。但是這並不具體,因為,真正進行通信的實體是在主機中的進程,是一個主機中的一個進程與另外一個主機中的一個進程在交換數據。IP協議雖然能把數據報文送到目的主機, 但是並沒有交付給主機的具體應用進程 。而 端到端的通信才應該是應用進程之間的通信

應用場景 :UDP協議比TCP協議的效率更高,TCP協議比UDP協議更加安全可靠。

下面主要對 數據傳輸出現錯誤/無應答/堵塞/超時/重復 等問題。

注意:TCP丟包:TCP是基於不可靠的網路實現可靠傳輸,肯定會存在丟包問題。如果在通信過程中,發現缺少數據或者丟包,那邊么 最大的可能性是程序發送過程或者接受過程中出現問題。

總結:為了滿足TCP協議不丟包,即保證可靠傳輸,規定如下:

注意:TCP丟包有三方面的原因,一是網路的傳輸質量不好,二是安全策略,三是伺服器性能瓶頸

先理解2個基礎概念:發送窗口、接收窗口

工作原理:

注意點:

關於滑動窗口的知識點:

滑動窗口中的數據類型:

ARQ解決的問題:出現差錯時,讓發送方重傳差錯數據:即 出錯重傳

類型:

流量控制和擁塞控制解決的問題:當接收方來不及接收收到的數據時,可通知發送方降低發送數據的效率:即 速度匹配

流量控制

注意:

擁塞控制

慢開始與擁塞避免

快重傳和快恢復

補充:流量控制和擁塞控制的區別

什麼情況造成TCP粘包和拆包?

解決TCP粘包和拆包的方法:

傳輸層無法保證數據的可靠傳輸 ,只能通過應用層來實現了。實現的方式可以參照tcp可靠性傳輸的方式,只是實現不在傳輸層,實現轉移到了應用層。

最簡單的方式是在應用層模仿傳輸層TCP的可靠性傳輸。 下面不考慮擁塞處理,可靠UDP的簡單設計。

https://www.jianshu.com/p/65605622234b
http://www.open-open.com/lib/view/open1517213611158.html
https://blog.csdn.net/dangzhangjing97/article/details/81008836
https://blog.csdn.net/qq_30108237/article/details/107057946
https://www.jianshu.com/p/6c73a4585eba

Ⅲ 【tcp】心跳檢測,保活機制

為什麼要心跳檢查?

因為目前討論的數據連接場景,都是無源連接,排除NAT的情況,連接就是存在於src和dest兩端OS中的狀態機,為什麼會要用無源連接呢,有源是連接建立帶寬就分配好了,不傳有效數據這個帶寬也被佔用著,這不就浪費了,虛擬信號時代的電話就是有源的。

心跳檢查是兩端都要做的,不做的那一端一樣存在狀態不對而不自知的情況。

狀態機在兩端是有可能不一致的,比如一端認為這條連接已經銷毀,另外一端可能認為仍有效。心跳機制的作用之一就是解決這種不一致的情況,類似「校對」的作用。

在瀏覽器上請求一個需要長時間才得到結果的請求,最後返回超時錯誤。

你說的情況我們經常遇到,我估計你說的就是客戶端自己的超時設置,也就是如果http響應無法在限定時間內完成(比如1秒內),那麼客戶端應用程序自己會報timeout錯誤。

這應該不是中間設備做了reset,因為如果是那樣,這個中間設備應該會給客戶端和服務端都發TCP RST,然後客戶端報錯會變成ECONNRESET這種(ECONNRESET是linux的網路協議棧報給用戶空間程序的報錯)。

心跳消息顯示push ack是為何呢?

按照TCP協議(參考RFC793)規定,操作系統收到有PSH標志位的報文後,這些報文不會被駐留在接收緩沖區,而是要立即通知用戶空間程序來接收。這樣對於用戶空間程序及時收發處理心跳報文是有利的。

AWS的nlb keep-alive最大是350s,我們的服務端keep-alive是默認配置,客戶端使用了連接池,也進行了探測,但是有個騷操作是隨機選取池子裡面的一個鏈接進行探測,然後那些超過350s還沒探測的鏈接,再次使用就出問題了。

你說的「隨機選取池子裡面的一個鏈接進行探測」,我判斷是健康檢查,就是業務健康性(類似k8s的readiness probe),而不是keepalive。

如果是這樣的話,這個健康檢查確實不是為保活而生的,也很難達到保活的目的。建議這樣做設置:client idle timeout < LB idle timeout < server idle timeout,這樣可以盡可能的保證不出現連接失效的情況。

這里說的「保活時間」,不是心跳包的間隔,而是空閑保活時間,idle timeout。

保活機制:心跳包異常導致應用重啟?

https://time.geekbang.org/column/article/482610

如何解決 Keep-Alive 導致 ECONNRESET 的問題

https://zhuanlan.hu.com/p/86953757

解決使用 KeepAlive Agent 遇到的 ECONNRESET

https://zhuanlan.hu.com/p/34147188

Ⅳ tcp連接的斷開

TCP的斷開就是經過四次揮手:

這是正常的情況,客戶端主動tcp連接斷開的過程。客戶端先是發送一個FIN為一的報文,然後進入FIN_WAIT_1的狀態。
伺服器收到FIN報文後,發送一個ACK報文,然後進入CLOSED_WAIT狀態。
客戶端收到伺服器的ACK報文進入FIN_WAIT_2狀態。
等到伺服器覺得他數據處理好了,可以關閉的時候,會發送一個FIN報文,然後進入LAST_ACK。等待最後一個應答。
讓客戶端收到伺服器FIN報文,就進入TIME_WAIT狀態了,隨後發送最後一個ACK報文,然後close。
客戶端再等待2msl後也自己主動關閉。而只有主動關閉的情況下,才會有TIME_WAIT。

那麼為什麼四次揮手需要四次呢?
三次握手其實就是在第二次把ACK和SYN兩個報文合並成一個發,但是斷開的過程可能還有一方需要處理下數據,需要延長點時間,等處理好再發FIN,所以就比三次握手多了一次。

這里還有一個問題,為什麼需要TIME_WAIT,然後到close需要2msl的時間呢?

先說下什麼是MSL,也就是報文的最長生存時間,超過這個時間的報文就要被丟棄掉。tcp是基於ip的,ip上有個生存時間TTL,是ip報文可以經過的最大路由數量,每經過一個路由就減1,減到0,ip報文就丟棄掉,然後通過ICMP通知源主機,我們的ping也算是經過這個。當然msl和ttl還是有區別的,msl是時間,ttl是路由數量,msl也是大於等於ttl的。在linux中,2msl默認是60秒。

前文也說了,只有主動發起斷開連接的進程才會有time wait狀態。time wait+2msl有兩個原因:
1.防止舊連接的數據包

像這個seq 301的包,如果因為網路的原因被延遲了,而沒有time wait或者很短,那麼連接斷開後,又建立新的連接,這個時候這個包到了,可能就導致數據紊亂了。而2msl可以保證兩個方向的包在斷開前丟棄掉。

2.保證正確的斷開連接
2msl的時間也是保證第四個報文的ack可以被被動關閉方接收到。

如圖,假設time wait比較短或者沒有,當最後的ack報文丟失的時候。客戶端已經close了,而伺服器一直處於last ack的狀態。這樣連接就不能正常斷開了。而如果有time wait +2msl這個情況就可以避免。假設伺服器沒有收到最後一個ack報文,伺服器會重發FIN等待客戶端的ack。
這樣就可以保證不會出現一端斷開,另外一端沒有斷開的情況了。

有時候我們在伺服器上會看到很多time wait。time wait一般就是伺服器主動發起的斷開請求才會產生的狀態。所以time wait過多,第一個是系統資源會大量消耗,還有是埠如果占的太多,會導致沒辦法創建新連接。這個時候可以把linux的net.ipv4.tcp_tw_reuse開啟,置為1,可以復用time wait超過1秒的連接。

這邊再說說tcp的保活機制。也就是怎麼長期維持客戶端和服務端的連接。
在一個時間段內,如果沒有連接等相關活動,tcp的保活機制會定期發探測報文,如果連續幾個探測報文就沒有回應,就將錯誤信息報告給系統,系統通知上層應用。

在 Linux 內核可以有對應的參數可以設置保活時間、保活探測的次數、保活探測的時間間隔,以下都為
默認值:
tcp_keepalive_time=7200:表示保活時間是 7200 秒(2⼩時),也就 2 小時內如果沒有任何連接
相關的活動,則會啟動保活機制
tcp_keepalive_intvl=75:表示每次檢測間隔 75 秒;
tcp_keepalive_probes=9:表示檢測 9 次無響應,認為對⽅方是不不可達的,從⽽而中斷本次的連接。
也就是說在 Linux 系統中,最少需要經過 2 小時 11 分 15 秒才可以發現一個「死亡」連接。
當然這個時間也可以自己配置。

Ⅳ tcp連接plc經常中斷

使用TCP/IP協議連接PLC時如果經常出現通訊中斷的情況,那麼就要做出如下檢查,以確定問題所在。

首先,檢查網路連接線的好壞,從外觀上判斷其是否有破損,擠壓,或其它損壞現象,若直觀查看無法判斷最好使用測線儀進行測試,這樣更為准確。

其次,檢查電腦網卡,系統是否有報警故障,網卡運行是否正常,電腦主機是否有腐蝕,灰塵等環境因素造成的系統運行卡頓。

最後,通過網路測試查看數據發送和接收的速度,並且要查看周圍是否有其他網路干擾情況

Ⅵ TCP keepalive 和 http keep-alive 以及心跳保活

HTTP的長連接和短連接本質上是TCP長連接和短連接。

短連接
短連接,顧名思義,與長連接的區別就是,客戶端收到服務端的響應後,立刻發送FIN消息,主動釋放連接。也有服務端主動斷連的情況,凡是在一次消息交互(發請求-收響應)之後立刻斷開連接的情況都稱為短連接。

長連接/http keep-alive
也叫持久連接,即一個TCP連接服務多次請求,在TCP層握手成功後,不立即斷開連接,並在此連接的基礎上進行多次消息(包括心跳)交互,直至連接的任意一方(客戶端OR服務端)主動斷開連接,此過程稱為一次完整的長連接。

在HTTP/1.0中得到了初步的支持,客戶端在請求header中攜帶Connection:Keep-Alive,即是在向服務端請求持久連接。如果服務端接受持久連接,則會在響應header中同樣攜帶Connection: Keep-Alive,這樣客戶端便會繼續使用同一個TCP連接發送接下來的若干請求。(Keep-Alive的默認參數是[timout=5, max=100],即一個TCP連接可以服務至多5秒內的100次請求)

HTTP/1.1開始,即使請求header中沒有攜帶Connection: Keep-Alive,傳輸也會默認以持久連接的方式進行,只有加入"Connection: close "後,才關閉。

http keepalive是客戶端瀏覽器與服務端httpd守護進程協作的結果。

TCP中的KeepAlive
  TCP協議的實現中,提供了KeepAlive報文,用來探測連接的對端是否存活。在應用交互的過程中,可能存在以下幾種情況:

客戶端或伺服器意外斷電,死機,崩潰,重啟;

中間網路已經中斷,而客戶端與伺服器並不知道;

利用保活探測功能,可以探知這種對端的意外情況,從而保證在意外發生時,可以釋放半打開的TCP連接。TCP保活報文交互過程如下:

因此,KeepAlive並不適用於檢測雙方存活的場景,這種場景還得依賴於應用層的心跳。 應用層心跳也具備著更大的靈活性,可以控制檢測時機,間隔和處理流程,甚至可以在心跳包上附帶額外信息。

應用層心跳是檢測連接有效性以及判斷雙方是否存活的有效方式 。但是心跳過於頻繁會帶來 耗電和耗流量 的弊病,心跳頻率過低則會影響連接檢測的實時性。業內關於心跳時間的設置和優化,主要基於如下幾個因素:

理想的情況下,客戶端應當以略小於NAT超時時間的間隔來發送心跳包。 根據微信團隊測試的一些數據,一些常用網路的NAT超時時間如下表所示:

TCP的KeepAlive機制意圖在於保活、心跳,檢測連接錯誤

如何快速區分當前連接使用的是長連接還是短連接
1、凡是在一次完整的消息交互(發請求-收響應)之後,立刻斷開連接(有一方發送FIN消息)的情況都稱為短連接;

2、長連接的一個明顯特徵是會有心跳消息(也有沒有心跳的情況),且一般心跳間隔都在30S或者1MIN左右,用wireshark抓包可以看到有規律的心跳消息交互(可能會存在毫秒級別的誤差)。

什麼時候用長連接,短連接?
1、需要頻繁交互的場景使用長連接,如即時通信工具(微信/QQ,QQ也有UDP),相反則使用短連接,比如普通的web網站,只有當瀏覽器發起請求時才會建立連接,伺服器返回相應後,連接立即斷開。

2、維持長連接會有一定的系統開銷,用戶量少不容易看出系統瓶頸,一旦用戶量上去了,就很有可能把伺服器資源(內存/CPU/網卡)耗盡,所以使用需謹慎。

keep-alive與TIME_WAIT
使用http keep-alvie,可以減少服務端TIME_WAIT數量(因為由服務端httpd守護進程主動關閉連接)。道理很簡單,相較而言,啟用keep-alive,建立的tcp連接更少了,自然要被關閉的tcp連接也相應更少了。

短連接和長鏈接 圖:

參考: https://caofengbin.github.io/2018/03/16/dhcp-and-nat/#4-%E5%BD%B1%E5%93%8D%E5%BF%83%E8%B7%B3%E9%A2%91%E7%8E%87%E7%9A%84%E5%85%B3%E9%94%AE%E5%9B%A0%E7%B4%A0

https://blog.csdn.net/hengyunabc/article/details/44310193

http://wingjay.com/2018/12/05/android-arch-long-link/

https://www.levicc.com/2018/06/30/yi-dong-an-wang-luo-you-hua/

能被我參考的都很優秀,哈哈

Ⅶ tcp連接狀態詳解

unix的哲學是一切皆文件,可以把socket看成是一種特殊的文件,而一些socket函數就是對其進行的操作api(讀/寫IO、打開、關閉)。我們知道普通文件的打開操作(open)返回一個文件描述字,與之類似,socket()用於創建一個socket描述符(socket descriptor),它唯一標識一個socket。

當我們調用socket創建一個socket時,返回的socket描述字它存在於協議族(address family,AF_XXX)空間中,但沒有一個具體的地址。如果想要給它賦值一個地址,就必須調用bind()函數,

 sockfd即socket描述字,它是通過socket()函數創建了,唯一標識一個socket。bind()函數就是將給這個描述字綁定一個名字。
    在將一個地址綁定到socket的時候,需要先將主機位元組序轉換成為網路位元組序,而不要假定主機位元組序跟網路位元組序一樣使用的是Big-Endian。由於這個問題曾引發過不少血案,謹記對主機位元組序不要做任何假定,務必將其轉化為網路位元組序再賦給socket。
    這里的主機位元組序就是我們平常說的大端和小端模式:不同的CPU有不同的位元組序類型,這些位元組序是指整數在內存中保存的順序,這個叫做主機序。引用標準的Big-Endian和Little-Endian的定義如下:

   listen函數的第一個參數即為要監聽的socket描述字,第二個參數為socket可以接受的排隊的最大連接個數。listen函數表示等待客戶的連接請求。

  connect函數的第一個參數即為客戶端的socket描述字,第二參數為伺服器的socket地址,第三個參數為socket地址的長度。客戶端通過調用connect函數來建立與TCP伺服器的連接。

 TCP伺服器端依次調用socket()、bind()、listen()之後,就會監聽指定的socket地址了。TCP客戶端依次調用socket()、connect()之後就向TCP伺服器發送連接請求。TCP伺服器監聽到這個請求之後,就會調用accept()函數去接收請求,這樣連接就建立好了(在connect之後就建立好了三次連接),之後就可以開始進行類似於普通文件的網路I/O操作了。

 如果accpet成功,那麼其返回值是由內核自動生成的一個全新的描述字,代表與客戶的TCP連接。
 accept的第一個參數為伺服器的socket描述字,是伺服器開始調用socket()函數生成的,稱為監聽socket描述字;而accept函數返回的是已連接的socket描述字。一個伺服器通常通常僅僅只創建一個監聽socket描述字,它在該伺服器的生命周期內一直存在。內核為每個由伺服器進程接受的客戶連接創建了一個已連接socket描述字,當伺服器完成了對某個客戶的服務,相應的已連接socket描述字就被關閉。

 read函數是負責從fd中讀取內容.當讀成功時,read返回實際所讀的位元組數,如果返回的值是0表示已經讀到文件的結束了,小於0表示出現了錯誤。如果錯誤為EINTR說明讀是由中斷引起的,如果是ECONNREST表示網路連接出了問題。

 write函數將buf中的nbytes位元組內容寫入文件描述符fd.成功時返回寫的位元組數。失敗時返回-1,並設置errno變數。 在網路程序中,當我們向套接字文件描述符寫時有倆種可能。1)write的返回值大於0,表示寫了部分或者是全部的數據。2)返回的值小於0,此時出現了錯誤

 在伺服器與客戶端建立連接之後,會進行一些讀寫操作,完成了讀寫操作就要關閉相應的socket描述字,類似於操作完打開的文件要調用fclose關閉打開的文件。

 close一個TCP socket的預設行為時把該socket標記為已關閉,然後立即返回到調用進程。該描述字不能再由調用進程使用,也就是說不能再作為read或write的第一個參數

 close操作只是使相應socket描述字的引用計數-1,只有當引用計數為0的時候,才會觸發TCP客戶端向伺服器發送終止連接請求。

 我們知道tcp建立連接要進行「三次握手」,即交換三個分組。大致流程如下:

客戶端向伺服器發送一個SYN J

伺服器向客戶端響應一個SYN K,並對SYN J進行確認ACK J+1

客戶端再想伺服器發一個確認ACK K+1

socket中TCP的四次握手釋放連接詳解

 某個應用進程首先調用close主動關閉連接,這時TCP發送一個FIN M;另一端接收到FIN M之後,執行被動關閉,對這個FIN進行確認。一段時間之後,服務端調用close關閉它的socket。這導致它的TCP也發送一個FIN N;接收到這個FIN的源發送端TCP對它進行確認,這樣每個方向上都有一個FIN和ACK。

為什麼要三次握手

由於tcp連接是全雙工的,存在著雙向的讀寫通道,每個方向都必須單獨進行關閉。當一方完成它的數據發送任務後就可以發送一個FIN來終止這個方向的連接。收到FIN只意味著這個方向上沒有數據流動,但並不表示在另一個方向上沒有讀寫,所以要雙向的讀寫關閉需要四次握手,

    3. time_wait狀態如何避免?

首先伺服器可以設置SO_REUSEADDR套接字選項來通知內核,如果埠忙,但TCP連接位於TIME_WAIT狀態時可以重用埠。在一個非常有用的場景就是,如果你的伺服器程序停止後想立即重啟,而新的套接字依舊希望使用同一埠,此時SO_REUSEADDR選項就可以避免TIME_WAIT狀態。

1.客戶端連接伺服器的80服務,這時客戶端會啟用一個本地的埠訪問伺服器的80,訪問完成後關閉此連接,立刻再次訪問伺服器的
80,這時客戶端會啟用另一個本地的埠,而不是剛才使用的那個本地埠。原因就是剛才的那個連接還處於TIME_WAIT狀態。

2.客戶端連接伺服器的80服務,這時伺服器關閉80埠,立即再次重啟80埠的服務,這時可能不會成功啟動,原因也是伺服器的連
接還處於TIME_WAIT狀態。
實戰分析:

狀態描述:

CLOSED:無連接是活動的或正在進行
LISTEN:伺服器在等待進入呼叫
SYN_RECV:一個連接請求已經到達,等待確認
SYN_SENT:應用已經開始,打開一個連接
ESTABLISHED:正常數據傳輸狀態
FIN_WAIT1:應用說它已經完成
FIN_WAIT2:另一邊已同意釋放
ITMED_WAIT:等待所有分組死掉
CLOSING:兩邊同時嘗試關閉
TIME_WAIT:另一邊已初始化一個釋放
LAST_ACK:等待所有分組死掉</pre>

命令解釋:

如何盡量處理TIMEWAIT過多?

編輯內核文件/etc/sysctl.conf,加入以下內容:
net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防範少量SYN攻擊,默認為0,表示關閉;
net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
net.ipv4.tcp_fin_timeout 修改系默認的 TIMEOUT 時間</pre>

然後執行 /sbin/sysctl -p 讓參數生效.
/etc/sysctl.conf是一個允許改變正在運行中的Linux系統的介面,它包含一些TCP/IP堆棧和虛擬內存系統的高級選項,修改內核參數永久生效。

簡單來說,就是打開系統的TIMEWAIT重用和快速回收。

  本文主要講述了socket的主要api,以及tcp的連接過程和其中各個階段的連接狀態,理解這些是更深入了解tcp的基礎!

Ⅷ C#的TCP連接,怎樣保持客戶端和伺服器端一直連接著

只要不執行Socket.Shutdown(),Socket.Close().就會一直連著。當然有時候網路不穩定,可能會失去連接,這時候你使用握手協議,始終監控連接即可。具體做法可以google一下。

Ⅸ 一文帶你搞定TCP揮手

TCP斷開連接,需要經歷四次揮手,通信的雙方都可主動斷開連接,斷開連接通信的雙方佔用的資源將會被釋放。

為什麼回收需要四次

原因是客戶端在主動發起FIN報文以後僅表示客戶端不再主動發送數據了但是還可以接收數據。伺服器在響應ACK報文以後,還有可能有數據還在處理且需要發送給客戶端,因此當伺服器處理完這些數據以後才能發送FIN報文表示同意關閉連接。

因此服務端的ACK和FIN報文需要分開發送,揮手也就變成了4次。

什麼是MSL和TTL

TTL是IP頭部中的一個欄位,是指IP數據報可以經過的最大路由數,每經過一個路由器都需要減1,當TTL值為0時數據報就會被丟棄,同時發送ICMP報文給源主機。TTL的單位是路由跳數。

MSL是報文在網路中存在的最長時間,超過該時間就會被丟棄。

為什麼TIME_WAIT需要經歷2MSL後才可以變為CLOSED

網路中存在的發送方數據包,首先需要發送給服務端,服務端在處理完以後又會將相應發送給客戶端,所以總共需要2個倍的時間。

2MSL的時間是從客戶端接收到FIN報文並且發送ACK報文時開始的。如果此時ACK報文沒有被服務端接收到觸發了服務端的超時重傳,客戶端又再次收到了FIN報文,那麼2MSL將重新開始計時。

LINUX中默認一個MSL是30s,也就是說TIME_WAIT的時間是60s。

為什麼需要TIME_WAIT狀態

主動發起連接中斷的一方需要有TIME_WAIT狀態,主要是以下原因:

防止舊連接的數據包被收到

假設沒有TIME_WAIT狀態,如果有相同的埠的TCP連接被服用後,上圖中被延遲SEQ=301的數據包抵達了客戶端,客戶端是有可能正常接收該報文的,此時就會產生數據錯亂現象。

但通過2MSL的等待時間,通信雙方的數據包都可以在網路中消失,新的數據包一定是新連接的。

保證連接正確關閉

通過等待2MSL的時間確保最後一次ACK報文被被動斷開連接的一方收到,從而正常關閉。

上圖如果服務端沒有收到最後一個ACK報文會處於LAST_ACK狀態,如果此時客戶端發起了一個新的SYN報文請求建立連接,服務端會發送RST報文給客戶端,連接建立失敗。

但是通過等待2MSL的時間會解決上述問題,因為假設服務端沒有收到最後一次ACK報文,會觸發超時重傳重新發送FIN報文並等待新的ACK報文。客戶端在收到新的FIN報文時會重新發送ACK報文並刷新2MSL的計時,最終能夠保證服務端的連接能夠正常關閉。

TIME_WAIT過多的弊端

伺服器如果有TIME_WAIT狀態的連接,說明TCP連接的斷開是由服務端發起的,此時如果TIME_WAIT的連接過多,將會出現以下問題:

TIME_WAIT的優化主要有以下幾種方式,每種方式都有利有弊:

打開net.ipv4.tcp_tw_reuse和net.ipv4.tcp_timestamps選項

參數開啟以後,可以復用處於TIME_WAIT的Socket給新的連接使用。

tcp_tw_reuse的功能只能用於連接發起方,開啟該參數以後,在調用connect函數時,內核會隨機找一個time_wait超過1s的連接給新的連接復用。

net.ipv4.tcp_timestamp默認開啟,表示打開對TCP時間戳的支持。時間戳欄位存儲在TCP頭部的選項欄位中,用於記錄TCP發送方的時間戳和從對端接收到的最新時間戳。

net.ipv4.tcp_max_tw_buckets

當系統中的TIME_WAIT的連接數超過該項的值時,系統那個會將後面TIME_WAIT的連接重置,不推薦使用。

程序使用SO_LINGER

通過設置Sokcet的一些選項,來影響close方法的一些行為。

如果SO_LINGER中的onoff為非0,並且linger為0,調用close方法以後會立即發送一個RST報文給對方,TCP連接會直接跳過四次握手關閉。也過於暴力不推薦。

在某個時間段內,如果TCP連接上無任何活動,TCP保活機制開始生效,每隔一段時間就會發送一個探測報文,如果連續幾個探測報文都沒有收到響應,則認為TCP連接已死,系統內核會將錯誤信息通知給應用程序。

上述三個都是Linux中的默認值,也就是說Linux操作系統中至少經過2小時11分15秒才可以發現一個死亡連接。

Java中的ServerSokcet的初始化方法中有一個backlog參數,該參數在Linux2.2以前代表SYN隊列大小,但是在Linux 2.2以後就是全連接隊列的大小(accept隊列的大小)。

Socket的一些連接操作對應的tcp連接步驟

close方法對應的TCP四次揮手

閱讀全文

與伺服器tcp怎麼保活相關的資料

熱點內容
安卓手機微信發不出視頻怎麼弄 瀏覽:229
壓縮機專用工具 瀏覽:575
qtcreator可以編譯cp嗎 瀏覽:405
小項目是雲伺服器還是本地好 瀏覽:14
墨痕齋是什麼游戲的伺服器 瀏覽:942
word文件如何壓縮大小 瀏覽:279
遵義聯通伺服器地址是什麼 瀏覽:29
ansys約束命令流 瀏覽:814
解壓軟體電腦版如何下載 瀏覽:791
閃電匕首演算法球 瀏覽:692
linuxredis停止命令 瀏覽:670
大麥賬號怎麼加密 瀏覽:113
穿越火線怎麼找伺服器 瀏覽:526
秘密加密社交軟體app 瀏覽:256
c語言編譯器怎麼找文件 瀏覽:836
數學不好能編程嗎 瀏覽:254
微雲里的視頻加密 瀏覽:41
3大加密貨幣交易平台 瀏覽:647
鈑金激光切割機編程 瀏覽:496
vivo手機手電筒app在哪裡 瀏覽:787