導航:首頁 > 配伺服器 > 伺服器如何判斷報文重復

伺服器如何判斷報文重復

發布時間:2022-12-22 09:26:19

㈠ 分析tcp協議原理

原理四個主要方面:
一、tcp協議之連接建立、斷開
二、tcp協議之超時重傳
三、tcp協議之窗口管理
四、tcp協議之擁塞控制

TCP是一種面向有連接的協議,也就是說必須確認對方存在時才能發送數據而TCP通過檢驗和、序列號、確認應答、重發控制、連接管理、窗口控制等機制來實現可靠傳輸。

1. 目的:TCP三次握手是客戶端和伺服器總共發三個數據包,通過三個數據包來確認主動發送能力和被動接收能力是否正常。
2. 實質:通過指定的四元組(源地址、源埠、目標地址、目標埠)來建立TCP連接,同步雙方各自發送序列號seq和確認號ACK,同時也會交換窗口大小信息

三次握手過程的實現方式就是交換序列號seq。

隨便在網上找個地址,如果通過域名想看ip地址,可以ping下看連接。

① 192.168.3.7發送[SYN]報文段至222.169.228.146,告知序列號x為0。
② 222.169.228.146發送[SYN,ACK]報文段至192.168.3.7,告知序列號y為0,確認號ACK為x+1=1。
③192.168.3.7發送[ACK]報文段至222.169.228.146,告知確認號ACK為y+1=1。

報文段中的其他參數:
MSS=1460 :允許從對方接收到的最大報文段,圖中為1460位元組(指承載的數據,不包含報文段的頭部)。
win=8192 :滑動窗口的大小為8192位元組。
SACK_PERM=1 :開啟選擇確認。為什麼會使用SACK:tcp確認方式不是一段報文段一確認,而是採用累積確認方式。伺服器接收到的報文段無序所以序列號也是不連續,伺服器的接收隊列會出現空洞情況。為了解決空洞,提前了解當前空洞,應對丟失遺漏,採取重傳。提前了解方式就是通過SACK選項信息,SACK信息包含接收方已經成功接收的數據塊的序列號范圍。而SACK_PERM欄位為1表明,選擇開啟了SACK功能。

網路層可能會出現丟失、重復、亂序的問題,tcp是提供可靠的數據傳輸服務的,為了保證數據的正確性,tcp協議會重傳它認為的已經丟失的包。重傳兩種機制:一種基於時間重傳,一種基於確認報文段提供的信息重傳。

RTT :數據完全發送完(完成最後一個比特推送到數據鏈路上)到收到確認信號的時間(往返時間)。
RTO :重傳超時時間(tcp發送數據時設置一個計時器,當計時器超時沒有收到數據確認信息,引發超時而重傳,判斷的標准就是RTO)。

思考:發送序列號為1、2、3、4這4個報文段,但是出現了序列號2報文段丟失,怎麼辦?

發送端接收到seq1的確認報文(ACK=2)後,等待seq=2的確認報文。
接收端當收到序列號為3的報文(2已丟失),發送ack為4的確認報文,發送端正等待ack為2的確認報文,面對跳躍的報文,那麼發送端會一直等待,直到超出指定時間,重傳報文2。

為什麼不跳躍確認呢?
tcp是累積確認方式,如果確認報文3,那麼意味著報文1和報文2都已經成功接收。

超時處理方式:

思考:上面計時器是以時間為標准重傳,那麼可以通過確認報文的次數來決定重傳。

發送端接收到seq1的確認報文(ACK=2)後,等待seq=2的確認報文。
接收端收到報文3、4、5,但是沒收到報文2,那麼接收端發送三個ACK為2的確認報文,發送端收到這個三個確認報文,重傳報文2。

思考:如果快速重傳中丟失包的地方很多(報文2,報文,7,報文9,報文30,報文300....),那麼需要從頭到尾都重傳,這很蛋疼?

思考:SACK重傳對於接收到重復數據段怎樣運作沒有明確規定,通過DSACK重傳可以讓發送方知道哪些數據被重復接收了,而且明確是什麼原因造成的。

發送端沒有收到100-199的ACK包,超過指定時間,重傳報文。
接收端都已經收到200-299的發送報文了,又來100-199是重復報文。再向發送端發送一個ACK報文,設置SACK 100-199,告知發送端,已經收到了100-199包,只是回應ACK包丟失。

發送端發送包100-199,由於網路延遲,一直沒有達到接收端。
接收端連續發送三個ACK 200確認報文,觸發快速重傳,發送端收到了ACK 500的確認報文,表明之前的報文都已經交付成功。
接收端又收到了延遲的報文100-199,再次向發送端發送一個SACK 100-199的ACK 500報文。
發送端發現這是重復報文,判斷為網路延遲造成的。

計時器重傳:根據超時,重傳。
快速重傳:根據接收三次相同ACK報文,重傳。
選擇確認重傳:根據接收端提供的SACK信息,重傳。
DSACK重傳:根據重復報文,明確丟失ACK報文還是網路延遲。

Category1:已發送且已確認(已經收到ACK報文的數據)。
Category2:已發送但未收到確認。
Category3:即將發送。
Category4:窗口移動前都不能發送。

可用窗口:46-51位元組。
發送窗口:32-51位元組。

RCV.NXT:左邊界
RCV.WND:接收窗口
RCV.NXT+RCV.WND:右邊界
接收端接收到序列號小於左邊界,那麼被認為重復數據而被丟棄。
接收端接收到序列號大於右邊界,那麼被認為超出處理范圍,丟棄。
注意:tcp協議為累積ACK結構,只有當達到數據序列號等於左邊界時,數據才不會被丟棄。

如果窗口更新ACK丟失,對於發送端,窗口左邊界右移,已發送數據得到ACK確認之後,左右邊界距離減小,發送端窗口會減小,當左右邊界相等時,稱為零窗口。零窗口之後:接收端發送窗口更新能會發生窗口更新ACK丟失。

<<tcp/ip 詳解>>解釋:
TCP是通過接收端的通告窗口來實現流量控制的,通告窗口指示了接收端可接收的數據量。
當窗口值變為0時,可以有效阻止發送端繼續發送,直到窗口大小恢復為非零值。
當接收端重新獲得可用空間時,會給發送端傳輸一個窗口更新告知其可繼續發送數據。這樣的窗口更新通常都不包含數據(純ACK),接收端向發送端發送的窗口更新ACK可能丟失。結果雙方處於等待狀態,發生死鎖。

解決方案:
發送端會採用一個持續計時器間歇性地查詢接收端,看其窗口是否已增長。觸發窗口探測,強制要求接收端返回ACK。發送幾次探測,窗口大小還是0,那麼斷開連接。

出現SWS的情況:
① 接收端通告窗口太小。
② 發送端發送的數據太小。
解決方案:
① 針對接收端:不應通告小窗口值
[RFC1122]描述:在窗口可增至一個全長的報文段(接收端MSS)或者接收端緩存空間的一半(取兩者中較小值)之前,不能通告比當前窗口更大的窗口值。標准:min(MSS , 緩存空間/2)。
② 針對發送端:不應發送小的報文
至少滿足以下其一:
(1)可以發送MSS位元組的報文。
window size >= MSS或者 數據大小>=MSS
(2)數據段長度>=接收端通告過的最大窗口值的一半,才可以發送。
收到之前發送的數據的ack回包,再發送數據,否則一直攢數據。
(3) -1 沒有未經確認的在傳數據或者-2 連接禁用Nagle演算法

tcp基於ACK數據包中的通告窗口大小欄位實現了流量控制。
當網路大規模通信負載而癱瘓,默認網路進入擁塞狀態,減緩tcp的傳輸。發送方和接收方被要求承擔超負荷的通信任務時,採取降低發送速率或者最終丟棄部分數據的方法。

反映網路傳輸能力的變數稱為擁塞窗口(cwnd)。
通告窗口(awnd)。
發送窗口swnd=min(cwnd,awnd)

目的:tcp在用擁塞避免演算法探尋更多可用帶寬之前得到cwnd值,幫助tcp建立ACK時鍾。
[RFC5681] :在傳輸初始階段,由於未知網路傳輸能力,需要緩慢探測可用傳輸資源,防止短時間內大量數據注入導致擁塞。慢啟動演算法針對這一問題而設計。在數據傳輸之初或者重傳計時器檢測到丟包後,需要執行慢啟動。

擁塞窗口值:每收到一個ACK值,cwnd擴充一倍。所以假設沒有丟包且每個數據包都有相應ACK值,在k輪後swnd= ,成 指數增長

SMSS是發送方的最大段大小。

慢啟動階段,cwnd會指數增長,很快,幫助確立一個慢啟動闕值(ssthresh)。有了闕值,tcp會進入擁塞避免階段,cwnd每次增長值近似於成功傳輸的數據段大小,成 線性增長
實現公式:cwnd+=SMSS*SMSS/cwnd

剛建立連接使用慢啟動演算法,初始窗口為4,收到一次ACK後,cwnd變為8,再收到一次ACK後,cwnd變為16,依次繼續,32、64,達到闕值ssthresh為64。
開始使用擁塞避免演算法,設置ssthresh為ssthresh/2,值為32。重新從初始窗口4,線性遞增到ssthresh=32。

當cwnd < ssthresh時,使用慢啟動演算法
當cwnd > ssthresh時,使用擁塞避免演算法

應用快速恢復演算法時機:啟動快速重傳且正常未失序ACK段達到之前。啟動快速恢復演算法。
實現過程:
① 將ssthresh設置為1/2 cwnd,將cwnd設置為ssthresh+3*SMSS。
② 每接收一個重復ACK,cwnd值暫時增加1 SMSS。
③當接收到新數據ACK後,將cwnd設置為ssthresh。

參考:<<tcp/ip 詳解>>

㈡ 百度雲妙傳是如何分辨本地文件與伺服器上現有的文件完全一致才進行妙傳

什麼是秒傳?
秒傳是一種在網盤上常見的「忽略式」上傳方式,比如您上傳了一個文件名為aaa.exe,MD5為一個數,網盤上以前也有人上傳一個叫aaa.exe,MD5和您上傳的文件MD5碼一模一樣,所以這個文件上傳到伺服器上的時間就很短了,這是因為別人上傳過這個文件,您現在上傳這個文件,伺服器上有這個文件了,所以在伺服器把這個文件復制一份到您的網盤上就可以了。就好比,別人叫你做以前做過的事情,又有人今天找你來讓你做相同的事情,你是不是已有經驗,會很熟練,做的時間就快多了?在這里也是同理。
秒傳的原理詳細解釋
上傳到網盤的每個文件,伺服器都會校驗MD5碼。如果這個您上傳的文件MD5碼與已經存在於伺服器里的文件的MD5碼相同的話,網盤伺服器將會判斷成為重復文件,只需要復制副本保存在網盤上即可,無需重新保存,因為有過目前這個文件,於是很快完成上傳任務,並在有人需要下載的時候將原有的該文件的下載地址放出。這樣實現了伺服器的高效運作。
怎樣不秒傳?
把你要上傳的東西壓縮成RAR,東西上傳,伺服器會先做MD5校驗,如果伺服器上有一樣的東西,它就直接給你個新地址,其實你下載的都是伺服器上的同一個文件,想要不秒傳,其實只要讓MD5改變,就是對文件本身做一下修改(改名字不行),例如一個文本文件,你多加幾個字,MD5就變了,就不會秒傳了。
但是有些文件我們不好改變,也不想改變,那其實只要壓縮一下,MD5就變了,而下載的人也能獲得最原始的資料,不過就是加壓要花費一點時間。希望對你有所幫助,答題不易請點採納。

㈢ 如何通過HTTP狀態判斷伺服器運營狀態

HTTP狀態碼(HTTP Status Code)是用以表示網頁伺服器HTTP響應狀態的3位數字代碼。它由 RFC 2616 規范定義的,並得到RFC 2518、RFC 2817、RFC 2295、RFC 2774、RFC 4918等規范擴展。

所有狀態碼的第一個數字代表了響應的五種狀態之一。

1xx 消息

這一類型的狀態碼,代表請求已被接受,需要繼續處理。這類響應是臨時響應,只包含狀態行和某些可選的響應頭信息,並以空行結束。由於 HTTP/1.0 協議中沒有定義任何 1xx 狀態碼,所以除非在某些試驗條件下,伺服器禁止向此類客戶端發送 1xx 響應。

100 Continue

客戶端應當繼續發送請求。這個臨時響應是用來通知客戶端它的部分請求已經被伺服器接收,且仍未被拒絕。客戶端應當繼續發送請求的剩餘部分,或者如果請求已經完成,忽略這個響應。伺服器必須在請求完成後向客戶端發送一個最終響應。

101 Switching Protocols

伺服器已經理解了客戶端的請求,並將通過 Upgrade 消息頭通知客戶端採用不同的協議來完成這個請求。在發送完這個響應最後的空行後,伺服器將會切換到在 Upgrade 消息頭中定義的那些協議。

只有在切換新的協議更有好處的時候才應該採取類似措施。例如,切換到新的 HTTP 版本比舊版本更有優勢,或者切換到一個實時且同步的協議以傳送利用此類特性的資源。

102 Processing

由WebDAV(RFC 2518)擴展的狀態碼,代表處理將被繼續執行。

2xx 成功

這一類型的狀態碼,代表請求已成功被伺服器接收、理解、並接受。

200 OK

請求已成功,請求所希望的響應頭或數據體將隨此響應返回。

201 Created

請求已經被實現,而且有一個新的資源已經依據請求的需要而建立,且其 URI 已經隨 Location 頭信息返回。假如需要的資源無法及時建立的話,應當返回 '202 Accepted'。

202 Accepted

伺服器已接受請求,但尚未處理。正如它可能被拒絕一樣,最終該請求可能會也可能不會被執行。在非同步操作的場合下,沒有比發送這個狀態碼更方便的做法了。

返回202狀態碼的響應的目的是允許伺服器接受其他過程的請求(例如某個每天只執行一次的基於批處理的操作),而不必讓客戶端一直保持與伺服器的連接直到批處理操作全部完成。在接受請求處理並返回202狀態碼的響應應當在返回的實體中包含一些指示處理當前狀態的信息,以及指向處理狀態監視器或狀態預測的指針,以便用戶能夠估計操作是否已經完成。

203 Non-Authoritative Information

伺服器已成功處理了請求,但返回的實體頭部元信息不是在原始伺服器上有效的確定集合,而是來自本地或者第三方的拷貝。當前的信息可能是原始版本的子集或者超集。例如,包含資源的元數據可能導致原始伺服器知道元信息的超級。使用此狀態碼不是必須的,而且只有在響應不使用此狀態碼便會返回200 OK的情況下才是合適的。

204 No Content

伺服器成功處理了請求,但不需要返回任何實體內容,並且希望返回更新了的元信息。響應可能通過實體頭部的形式,返回新的或更新後的元信息。如果存在這些頭部信息,則應當與所請求的變數相呼應。

如果客戶端是瀏覽器的話,那麼用戶瀏覽器應保留發送了該請求的頁面,而不產生任何文檔視圖上的變化,即使按照規范新的或更新後的元信息應當被應用到用戶瀏覽器活動視圖中的文檔。

由於204響應被禁止包含任何消息體,因此它始終以消息頭後的第一個空行結尾。

205 Reset Content

伺服器成功處理了請求,且沒有返回任何內容。但是與204響應不同,返回此狀態碼的響應要求請求者重置文檔視圖。該響應主要是被用於接受用戶輸入後,立即重置表單,以便用戶能夠輕松地開始另一次輸入。

與204響應一樣,該響應也被禁止包含任何消息體,且以消息頭後的第一個空行結束。

206 Partial Content

伺服器已經成功處理了部分 GET 請求。類似於 FlashGet 或者迅雷這類的 HTTP 下載工具都是使用此類響應實現斷點續傳或者將一個大文檔分解為多個下載段同時下載。

該請求必須包含 Range 頭信息來指示客戶端希望得到的內容範圍,並且可能包含 If-Range 來作為請求條件。

響應必須包含如下的頭部域:

Content-Range 用以指示本次響應中返回的內容的范圍;如果是 Content-Type 為 multipart/byteranges 的多段下載,則每一 multipart 段中都應包含 Content-Range 域用以指示本段的內容範圍。假如響應中包含 Content-Length,那麼它的數值必須匹配它返回的內容範圍的真實位元組數。

Date

ETag 和/或 Content-Location,假如同樣的請求本應該返回200響應。

Expires, Cache-Control,和/或 Vary,假如其值可能與之前相同變數的其他響應對應的值不同的話。

假如本響應請求使用了 If-Range 強緩存驗證,那麼本次響應不應該包含其他實體頭;假如本響應的請求使用了 If-Range 弱緩存驗證,那麼本次響應禁止包含其他實體頭;這避免了緩存的實體內容和更新了的實體頭信息之間的不一致。否則,本響應就應當包含所有本應該返回200響 應中應當返回的所有實體頭部域。

假如 ETag 或 Last-Modified 頭部不能精確匹配的話,則客戶端緩存應禁止將206響應返回的內容與之前任何緩存過的內容組合在一起。

任何不支持 Range 以及 Content-Range 頭的緩存都禁止緩存206響應返回的內容。

207 Multi-Status

由WebDAV(RFC 2518)擴展的狀態碼,代表之後的消息體將是一個XML消息,並且可能依照之前子請求數量的不同,包含一系列獨立的響應代碼。

3xx 重定向

這類狀態碼代表需要客戶端採取進一步的操作才能完成請求。通常,這些狀態碼用來重定向,後續的請求地址(重定向目標)在本次響應的 Location 域中指明。

當且僅當後續的請求所使用的方法是 GET 或者 HEAD 時,用戶瀏覽器才可以在沒有用戶介入的情況下自動提交所需要的後續請求。客戶端應當自動監測無限循環重定向(例如:A->A,或者A->B->C->A),因為這會導致伺服器和客戶端大量不必要的資源消耗。按照 HTTP/1.0 版規范的建議,瀏覽器不應自動訪問超過5次的重定向。

300 Multiple Choices

被請求的資源有一系列可供選擇的回饋信息,每個都有自己特定的地址和瀏覽器驅動的商議信息。用戶或瀏覽器能夠自行選擇一個首選的地址進行重定向。

除非這是一個 HEAD 請求,否則該響應應當包括一個資源特性及地址的列表的實體,以便用戶或瀏覽器從中選擇最合適的重定向地址。這個實體的格式由 Content-Type 定義的格式所決定。瀏覽器可能根據響應的格式以及瀏覽器自身能力,自動作出最合適的選擇。當然,RFC 2616規范並沒有規定這樣的自動選擇該如何進行。

如果伺服器本身已經有了首選的回饋選擇,那麼在 Location 中應當指明這個回饋的 URI;瀏覽器可能會將這個 Location 值作為自動重定向的地址。此外,除非額外指定,否則這個響應也是可緩存的。

301 Moved Permanently

被請求的資源已永久移動到新位置,並且將來任何對此資源的引用都應該使用本響應返回的若干個 URI 之一。如果可能,擁有鏈接編輯功能的客戶端應當自動把請求的地址修改為從伺服器反饋回來的地址。除非額外指定,否則這個響應也是可緩存的。

新的永久性的 URI 應當在響應的 Location 域中返回。除非這是一個 HEAD 請求,否則響應的實體中應當包含指向新的 URI 的超鏈接及簡短說明。

如果這不是一個 GET 或者 HEAD 請求,因此瀏覽器禁止自動進行重定向,除非得到用戶的確認,因為請求的條件可能因此發生變化。

注意:對於某些使用 HTTP/1.0 協議的瀏覽器,當它們發送的 POST 請求得到了一個301響應的話,接下來的重定向請求將會變成 GET 方式。

302 Found

請求的資源現在臨時從不同的 URI 響應請求。由於這樣的重定向是臨時的,客戶端應當繼續向原有地址發送以後的請求。只有在Cache-Control或Expires中進行了指定的情況下,這個響應才是可緩存的。

新的臨時性的 URI 應當在響應的 Location 域中返回。除非這是一個 HEAD 請求,否則響應的實體中應當包含指向新的 URI 的超鏈接及簡短說明。

如果這不是一個 GET 或者 HEAD 請求,那麼瀏覽器禁止自動進行重定向,除非得到用戶的確認,因為請求的條件可能因此發生變化。

注意:雖然RFC 1945和RFC 2068規范不允許客戶端在重定向時改變請求的方法,但是很多現存的瀏覽器將302響應視作為303響應,並且使用 GET 方式訪問在 Location 中規定的 URI,而無視原先請求的方法。狀態碼303和307被添加了進來,用以明確伺服器期待客戶端進行何種反應。

303 See Other

對應當前請求的響應可以在另一個 URI 上被找到,而且客戶端應當採用 GET 的方式訪問那個資源。這個方法的存在主要是為了允許由腳本激活的POST請求輸出重定向到一個新的資源。這個新的 URI 不是原始資源的替代引用。同時,303響應禁止被緩存。當然,第二個請求(重定向)可能被緩存。

新的 URI 應當在響應的 Location 域中返回。除非這是一個 HEAD 請求,否則響應的實體中應當包含指向新的 URI 的超鏈接及簡短說明。

注意:許多 HTTP/1.1 版以前的 瀏覽器不能正確理解303狀態。如果需要考慮與這些瀏覽器之間的互動,302狀態碼應該可以勝任,因為大多數的瀏覽器處理302響應時的方式恰恰就是上述規范要求客戶端處理303響應時應當做的。

304 Not Modified

如果客戶端發送了一個帶條件的 GET 請求且該請求已被允許,而文檔的內容(自上次訪問以來或者根據請求的條件)並沒有改變,則伺服器應當返回這個狀態碼。304響應禁止包含消息體,因此始終以消息頭後的第一個空行結尾。

該響應必須包含以下的頭信息:

Date,除非這個伺服器沒有時鍾。假如沒有時鍾的伺服器也遵守這些規則,那麼代理伺服器以及客戶端可以自行將 Date 欄位添加到接收到的響應頭中去(正如RFC 2068中規定的一樣),緩存機制將會正常工作。

ETag 和/或 Content-Location,假如同樣的請求本應返回200響應。

Expires, Cache-Control,和/或 Vary,假如其值可能與之前相同變數的其他響應對應的值不同的話。

假如本響應請求使用了強緩存驗證,那麼本次響應不應該包含其他實體頭;否則(例如,某個帶條件的 GET 請求使用了弱緩存驗證),本次響應禁止包含其他實體頭;這避免了緩存了的實體內容和更新了的實體頭信息之間的不一致。

假如某個304響應指明了當前某個實體沒有緩存,那麼緩存系統必須忽視這個響應,並且重復發送不包含限制條件的請求。

假如接收到一個要求更新某個緩存條目的304響應,那麼緩存系統必須更新整個條目以反映所有在響應中被更新的欄位的值。

305 Use Proxy

被請求的資源必須通過指定的代理才能被訪問。 Location 域中將給出指定的代理所在的 URI 信息,接收者需要重復發送一個單獨的請求,通過這個代理才能訪問相應資源。只有原始伺服器才能建立305響應。

注意:RFC 2068中沒有明確305響應是為了重定向一個單獨的請求,而且只能被原始伺服器建立。忽視這些限制可能導致嚴重的安全後果。

306 Switch Proxy

在最新版的規范中,306狀態碼已經不再被使用。

307 Temporary Redirect

請求的資源現在臨時從不同的 URI 響應請求。由於這樣的重定向是臨時的,客戶端應當繼續向原有地址發送以後的請求。只有在Cache-Control或Expires中進行了指定的情況下,這個響應才是可緩存的。

新的臨時性的 URI 應當在響應的 Location 域中返回。除非這是一個 HEAD 請求,否則響應的實體中應當包含指向新的 URI 的超鏈接及簡短說明。因為部分瀏覽器不能識別307響應,因此需要添加上述必要信息以便用戶能夠理解並向新的 URI 發出訪問請求。

如果這不是一個 GET 或者 HEAD 請求,那麼瀏覽器禁止自動進行重定向,除非得到用戶的確認,因為請求的條件可能因此發生變化。

㈣ 如何偵伺服器的tcp返回數據

在平時的開發中,經常會碰到一些需要檢測tcp連接是否正常的場景。比如一個分布式的應用,一個調度任務的節點管理一堆用來跑業務的節點。當調度節點進行調度的時候,需要把任務分發給它認為正常的業務節點去執行。業務節點是否正常,一個重要的參考依據就是調度節點和業務節點之間的tcp連接是否正常。這時候就需要調度節點主動地去檢測tcp連接。常見的檢測方法有以下幾種

方案一、通過TCP協議的返回值進行判斷

<1> 利用select,把socket設置為非阻塞。然後使用select等待該socket的可讀事件。如果socket可讀,但是recv的返回值是0,則說明socket已經被對端斷開,這時候就可以調用close關閉socket。這里還要注意一點,recv還可能返回負數,這個代表socket操作出錯。但是仍然應該判斷一下errno是否為EINTR。如果errno是EINTR,則說明recv函數是被信號中斷返回的,這時候不能判斷socket的連接是否正常,也不應該調用close關閉socket。

<2> 利用poll的事件。poll本身提供了POLLHUP,POLLERR, POLLNVAL三個事件。如果文件描述符是socket,則POLLHUP代表socket已經斷開了連接,在TCP底層就是已經收到了FIN報文。POLLERR表示socket出現了錯誤,一般情況下是收到了rst報文,或者已經發送了rst報文。這兩種情況都應該調用close關閉socket。POLLNVAL代表socket沒有打開,這時不能使用close關閉它,而應該根據自己的業務做一些其他的操作。因為關閉一個未打開的socket會出錯。

這兩種方法都可以很精確地判斷tcp連接是否正常,但是仍然有很明顯的缺陷。就是它只可以根據TCP操作的返回值來進行判斷。如果TCP四次握手沒有正常被執行呢?比如連接對端機器直接掛了,那麼就不會發送FIN報文給這一端,select不會返回socket可讀,poll不會返回socket異常。那麼這個死鏈接將會永遠檢測不到。直到寫這個socket的時候,對端直接返回一個ret報文,這時才知道這個連接已經斷掉了。這就意味著tcp連接異常可能永遠檢測不到,或者檢測到的延遲非常大。這對於一些資源寶貴而且要求高性能的伺服器是不能接受的,比如游戲伺服器,比如搜索伺服器。方案二、在第一種方案的基礎上設置socket的 keep alive 機制

方案一的主要缺陷在於檢測不及時,或者根本檢測不到。TCP協議提供了keep alive機制。如果開啟了這個特性(暫時稱開啟了keep alive的一端為開啟端),在默認情況下,開啟的著一端的socket相關結構中會維護一個定時器,默認是2小時。如果在2小時內兩端沒有數據往來,那麼開啟端就會給另一端發送一個ack空報文。這時候分幾種情況:

<1> 對端機器可達,而且TCP相關組件運行正常。那麼對端就會給開啟端發送一個ack空報文。這時開啟端就知道對端是正常的,意味著tcp連接也沒有問題。開啟端會重新初始化定時器,等待下一個超時的到來。需要注意的是,如果兩端之間有數據往來,定時器也會被重新初始化為2個小時。

<2> 對端掛了,或者正在重啟,還沒有完全起來。或者對端伺服器不可達。 這種狀態的對端是不會響應這個ack的。開啟端的 keep alive 機制會把這種情況當探測超時來處理,並且重新發送ack到對端。當超時次數超過一定限制,keep alive 就認為這個tcp連接有問題。典型值是每次75秒,超時9次。

<3> 對端掛過,但是已經重啟完成。這時候發送這個ack和寫已經關閉的socket是一種情況,對端會返回一個rst報文,這樣開啟端就知道tcp連接出問題了。

可以看出 keep alive 機制彌補了方案一種不能判斷沒有進行正常四次揮手連接出現問題的缺陷。默認的發送超時和發送間隔都是可以調整的。

tcp_keepalive_time: KeepAlive的空閑時長,默認是2小時

tcp_keepalive_intvl: KeepAlive探測包的發送間隔,默認是75s

tcp_keepalive_probes: 在tcp_keepalive_time之後,沒有接收到對方確認,繼續發送保活探測包次數,默認是9次

這3個參數使用 setsockopt函數都是可以配置的。

方案二看似已經完美了,能夠比較精確而且及時地發現有問題的連接。但是還有2個缺點。第一個是 keep alive 機制看似牛逼,但是很多人不建議使用。因為上面說的3個參數很難根據業務場景給出合適的值,設置不好很容易對tcp連接狀態發生誤判,關閉了一個本來正常的連接。而且沒有一個主動通知應用層的方式。比如socket連接出錯了,TCP協議接到了rst,fin,或者keep alive判斷出socket有問題了,但是並不會主動去通知應用層,必須我們自己 recv socket或者等待錯誤事件才能得到這個錯誤。第二個是很多場景下,keep alive 檢測仍然不夠及時,比如對端掛了,最長需要等待 tcp_keepalive_intvl * tcp_keepalive_probes時間才可以檢測出來,而且這兩個值還不能設置得太小,太小了容易誤判。

方案三、應用層的心跳

這種形式的心跳設計就比較多樣化了,而且靈活,可以很好地適應業務場景。唯一的缺點就是要自己寫代碼。我目前接觸到的就是定期進行RPC調用。看RPC調用是否正常,如果返回錯誤或者拋出異常,就說明連接有問題。

㈤ HTTP請求報文和響應報文

維基網路:HTTP

一個HTTP請求報文由請求行(request line)、請求頭部(header)、空行和請求數據4個部分組成。

大致結構是這樣的:

一個簡單的例子:

請求行由三部分組成:請求方法,請求URL(不包括域名),HTTP協議版本

請求方法比較多:GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT

最常用的是GET和POST。

1) GET

傳遞參數長度受限制,因為傳遞的參數是直接表示在地址欄中,而特定瀏覽器和伺服器對url的長度是有限制的。

因此,GET不適合用來傳遞私密數據,也不適合拿來傳遞大量數據。

一般的HTTP請求大多都是GET。

2)POST

POST把傳遞的數據封裝在HTTP請求數據中,以名稱/值的形式出現,可以傳輸大量數據,對數據量沒有限制,也不會顯示在URL中。

表單的提交用的是POST。

3)HEAD

HEAD跟GET相似,不過服務端接收到HEAD請求時只返回響應頭,不發送響應內容。所以,如果只需要查看某個頁面的狀態時,用HEAD更高效,因為省去了傳輸頁面內容的時間。

4)DELETE

刪除某一個資源。

5)OPTIONS

用於獲取當前URL所支持的方法。若請求成功,會在HTTP頭中包含一個名為「Allow」的頭,值是所支持的方法,如「GET, POST」。

6)PUT

把一個資源存放在指定的位置上。

本質上來講, PUT和POST極為相似,都是向伺服器發送數據,但它們之間有一個重要區別,PUT通常指定了資源的存放位置,而POST則沒有,POST的數據存放位置由伺服器自己決定。

關於POST和PUT的區別以及請求方法的冪等性,請參考文章: http的7種請求方法和冪等性

7)TRACE

回顯伺服器收到的請求,主要用於測試或診斷。

8)CONNECT

CONNECT方法是HTTP/1.1協議預留的,能夠將連接改為管道方式的代理伺服器。通常用於 SSL 加密伺服器的鏈接與非加密的HTTP代理伺服器的通信。

 

1)HTTP/1.0

HTTP/1.0支持:GET、POST、HEAD三種HTTP請求方法。

2)HTTP/1.1

HTTP/1.1是當前正在使用的版本。該版本默認採用持久連接,並能很好地配合代理伺服器工作。還支持以管道方式同時發送多個請求,以便降低線路負載,提高傳輸速度。

HTTP/1.1新增了:OPTIONS、PUT、DELETE、TRACE、CONNECT五種HTTP請求方法。
 

請求頭部由關鍵字/值對組成,每行一對

常見的Content-Type:

 

multipart/form-data

用以支持向伺服器發送二進制數據,以便可以在 POST 請求中實現文件上傳等功能

現在用Postman向網路發送一個請求方式為 multipart/form-data 的POST包,請求報文是這樣的:

其中, boundary這個參數是分界線的意思,這個分界線參數具體是什麼你可以隨意自定義 ,建議定義復雜一點,因為這樣子才不會跟請求體中其它欄位重復。

上面的例子看出分界線=「--」+boundary

每個參數都由分界線分隔開,參數名(二進制數據還需要指明文件類型)和參數值之間有一行 空行 ,這個空行不能省略:

消息主體最後以 --boundary-- 標示結束。

更加詳細的解釋可以參考: Multipart/form-data

請求頭之後是一個空行,通知伺服器以下不再有請求頭

GET沒有請求數據,POST有。

與請求數據相關的最常使用的請求頭是 Content-Type 和 Content-Length 。

HTTP響應報文和請求報文的結構差不多,也是由四個部分組成:

狀態行也由三部分組成:伺服器HTTP協議版本,響應狀態碼,狀態碼的文本描述

格式:HTTP-Version Status-Code Reason-Phrase CRLF

比如:HTTP/1.1 200 OK

狀態碼:由3位數字組成,第一個數字定義了響應的類別

用304告訴緩存器資源沒有被修改,並且響應體是空的,不會浪費帶寬。

㈥ 如何防範tcp syn flood

SYN Flood是當前最流行的DoS(拒絕服務攻擊)與DDoS(分布式拒絕服務攻擊)的方式之一,它是利用TCP協議缺陷,發送大量偽造的TCP連接請求,從而使得被攻擊方資源耗盡(CPU滿負荷或內存不足)的攻擊方式,最終導致系統或伺服器宕機。
在討論SYN Flood原理前,我們需要從TCP連接建立的過程開始說起:
TCP與UDP不同,它是基於連接的,為了在服務端和客戶端之間傳送TCP數據,必須先建立一個虛擬電路,也就是TCP連接。也就是我們經常聽說的TCP協議中的三次握手(Three-way Handshake),建立TCP連接的標准過程如下:
首先,客戶端發送一個包含SYN標志的TCP報文,SYN即同步(Synchronize),同步報文會指明客戶端使用的埠以及TCP連接的初始序號;
其次,伺服器在收到客戶端的SYN報文後,將返回一個SYN+ACK(即確認Acknowledgement)的報文,表示客戶端的請求被接受,同時TCP初始序號自動加一。
最後,客戶端也返回一個確認報文ACK給伺服器端,同樣TCP序列號被加一,到此一個TCP連接完成。
SYN Flood攻擊正是利用了TCP連接的三次握手,假設一個用戶向伺服器發送了SYN報文後突然死機或掉線,那麼伺服器在發出SYN+ACK應答報文後是無法收到客戶端的ACK報文的(第三次握手無法完成),這種情況下伺服器端一般會重試(再次發送SYN+ACK給客戶端)並等待一段時間後丟棄這個未完成的連接,這段時間的長度我們稱為SYN Timeout,一般來說這個時間是分鍾的數量級(大約為30秒-2分鍾);一個用戶出現異常導致伺服器的一個線程等待1分鍾並不會對伺服器端造成什麼大的影響,但如果有大量的等待丟失的情況發生,伺服器端將為了維護一個非常大的半連接請求而消耗非常多的資源。我們可以想像大量的保存並遍歷也會消耗非常多的CPU時間和內存,再加上伺服器端不斷對列表中的IP進行SYN+ACK的重試,伺服器的負載將會變得非常巨大。如果伺服器的TCP/IP棧不夠強大,最後的結果往往是堆棧溢出崩潰。相對於攻擊數據流,正常的用戶請求就顯得十分渺小,伺服器疲於處理攻擊者偽造的TCP連接請求而無暇理睬客戶的正常請求,此時從正常客戶會表現為打開頁面緩慢或伺服器無響應,這種情況就是我們常說的伺服器端SYN Flood攻擊(SYN洪水攻擊)。
從防禦角度來講,存在幾種的解決方法:
第一種是縮短SYN Timeout時間,由於SYN Flood攻擊的效果取決於伺服器上保持的SYN半連接數,這個值=SYN攻擊的頻度 x SYN Timeout,所以通過縮短從接收到SYN報文到確定這個報文無效並丟棄改連接的時間,例如設置為20秒以下,可以成倍的降低伺服器的負荷。但過低的SYN Timeout設置可能會影響客戶的正常訪問。
第二種方法是設置SYN Cookie,就是給每一個請求連接的IP地址分配一個Cookie,如果短時間內連續受到某個IP的重復SYN報文,就認定是受到了攻擊,並記錄地址信息,以後從這個IP地址來的包會被一概丟棄。這樣做的結果也可能會影響到正常用戶的訪問。
上述的兩種方法只能對付比較原始的SYN Flood攻擊,縮短SYN Timeout時間僅在對方攻擊頻度不高的情況下生效,SYN Cookie更依賴於對方使用真實的IP地址,如果攻擊者以數萬/秒的速度發送SYN報文,同時利用SOCK_RAW隨機改寫IP報文中的源地址,以上的方法將毫無用武之地。

㈦ 區域網內有不同dhcp伺服器時,向某個dhcp伺服器發送request請求時,其他伺服器回了一個nak報文

你說的是一個廣播域中有多台DHCP伺服器嗎? 如果是這樣的話,你的各台DHCP伺服器的地址池一定不能重復,還有就是客戶端從最先啟動的DHCP伺服器的地址池裡拿地址。

㈧ TIME_WAIT過高的處理

相信很多人都遇到過伺服器出現大量TIME_WAIT的情況,大多數的解決辦法是sysctl修改如下參數

net.ipv4.tcp_timestamps = 1 #上述兩項生效的前提是TCP連接兩端都要啟用TCP時間戳

過一會發現TIME_WAIT數量直線下降後,服務貌似也沒出問題,ok問題解決!其實不然。想真正理解所謂「大量的TIME_WAIT的問題」,我們要先理解TIME_WAIT。

TIME_WAIT是有友好的,不是多餘的,是主動關閉TCP連接的一方在調用socker的close操作後最終會進入TIME_WAIT狀態。伺服器在處理客戶端請求的時候,如果你的程序設計為伺服器主動關閉,那麼你才有可能需要關注這個TIMEWAIT狀態過多的問題。如果你的伺服器設計為被動關閉,那麼你首先要關注的是CLOSE_WAIT。

換句話說:在一台負載均衡的伺服器上(以Nginx為例),客戶端向Nginx的請求,作為伺服器來看屬於被動連接;Nginx向Web伺服器的請求屬於主動連接。在討論TIME_WAIT優化時,我們應該關注的是主動連接,即Nginx對Web伺服器的連接。

1、防止前一個連接延遲的數據被後面復用的連接錯誤的接收;

2、可靠的關閉TCP連接;

關於TIME_WAIT作用的深入理解需要配合Socket連接五元組、RFC 793等概念,本文不重點討論,感興趣的童鞋請移步 老男孩博客 。

內核里有保存所有連接的一個hash table,這個hash table既包含TIME_WAIT狀態的連接,也包含其它狀態的連接。主要用於有新的數據到來的時候,從這個hash table里快速找到這條連接。還有一個hash table用來保存所有的bound ports,主要用於可以快速的找到一個可用的埠或者隨機埠。

因此,內核保存這些數據必然會佔用一定的內存,同理每次找到一個隨機埠需要遍歷一遍bound ports,必然需要一些CPU時間!

TIME_WAIT很多,既占內存又耗CPU,但其實進一步研究,1萬條TIME_WAIT連接,也就多消耗1M左右的內存,對於現在的伺服器來說已經不算什麼。至於CPU,也不至於因為1萬多的hash item就擔憂。最起碼在TIME_WAIT達到幾千的量級上不必過多緊張,因為TIME_WAIT所佔用的內存很少很少,同時記錄和尋找可用的local port所消耗的CPU也基本可以忽略。

TIME_WAIT的存在是很重要的,如果強制忽略TIME_WAIT,還是有很高的機率,造成數據粗亂,或者短暫性的連接失敗。比較直接的現象是,通過NAT後的IP大量訪問服務的時候容易出現靜置幾分鍾後連接失敗或者多個客戶端同時訪問有的訪問頻繁失敗的情況。

還有一種情況是:在 客戶端-伺服器 一對一的時候,沒有任何問題,但是當源IP是經過NAT後的地址或伺服器在負載均衡器後面時,源地址為同一ip假如恰巧先後兩次連接源埠相同,這台伺服器先後收到兩個包,第一個包的timestamp被伺服器保存著,第二個包又來了,一對比,發現第二個包的timestamp比第一個還老——客戶端時間不一致。伺服器基於PAWS,判斷第二個包是重復報文,丟棄之。反映出來的情況就是在伺服器上抓包,發現有SYN包,但伺服器就是不回ACK包,因為SYN包已經被丟棄了。可用如下命令驗證,查看輸出裡面的 packets rejects in established connections because of timestamp 一項的數量變化。

寫了這么多,那麼tw_recycle參數到底該怎麼用呢?在這里,引用 老男孩博客 里給出的兩個典型場景的配置方案作為參考

在這種情況下,因為負載均衡伺服器對Web伺服器的連接(注意,負載均衡器向Web伺服器發起的主動連接),TIME_WAIT大都出現在負載均衡伺服器上,所以,在負載均衡伺服器上的配置:

在這種情況下,Web伺服器變成TIME_WAIT的重災區。負載均衡對Web伺服器的連接,由Web伺服器首先關閉連接,TIME_WAIT出現在Web伺服器上;Web伺服器對DB伺服器的連接,由Web伺服器關閉連接,TIME_WAIT也出現在它身上,此時,負載均衡伺服器上的配置:

http://blog.oldboye.com/tcp-wait/

http://blog.chinaunix.net/uid-24517549-id-4048652.html

http://blog.chinaunix.net/uid-28337979-id-4107112.html

寫在最後,內核的優化不能想當然,需要配合相應的業務場景。當然,這是一個長期積累的過程,需要不斷的研究摸索,也需要眾位同道多多分享多多賜教!與君共勉!

轉自: https://blog.51cto.com/cangzihu/1888622

㈨ 如何判斷收到的報文是一個完整的IP數據報而不是某個lP數據報的分片

IP數據包的包頭存在三個bit的表示位,第一個標識位備用,中間位DF(Don』t Fragment),DF=0 表示能分片,DF=1 表示不能分片。最低位為MF(More Fragment) ,MF=1 表示後面還在傳輸數據報的分片, MF=0 表示最後一個報文段。

IP數據包還有一個片偏移的欄位,當 片偏移為0時,表示這個數據報文沒有分片,或者第一個分片。

兩者可以結合來進行判斷。

閱讀全文

與伺服器如何判斷報文重復相關的資料

熱點內容
有免費編譯軟體嗎 瀏覽:916
java互聯網公司 瀏覽:70
對弈下象棋的app哪裡好 瀏覽:707
有什麼食譜app推薦 瀏覽:471
python實現動態口令 瀏覽:825
我的世界電腦伺服器地址怎麼添加 瀏覽:850
傳奇地圖怎麼加密到pak 瀏覽:977
linux刪除mysql用戶 瀏覽:755
圖案設計pdf 瀏覽:584
pdf編輯器在線 瀏覽:471
華為雲雲耀伺服器如何關機 瀏覽:994
數字加密的歷史 瀏覽:613
宏傑文件夾打不開 瀏覽:819
施工日記app哪個好 瀏覽:566
什麼是壓縮機的排氣量 瀏覽:538
在哪個app可以預約一科考試 瀏覽:634
易語言vmp加殼源碼 瀏覽:513
閱讀前端框架源碼 瀏覽:14
我的世界命令方塊傳送指令 瀏覽:545
不能用start命令打開xp 瀏覽:927