解析 http 協議是否要處理粘包? 是否要考慮到收到的資料報為不符 http 協議格式的資料報的情況

時間 2021-06-01 05:46:41

1樓:

此外http協議有很多細節,會使互動不是一問一答那麼簡單,比如100 continue。再加上不少server / client / proxy 的實現比較奇葩,要做真正可用的系統還是都要處理

盡量用成熟庫去做吧

2樓:zanllp

每次看到這個就想懟,tcp是流。網路沒異常也不會出現資料丟失的情況,檢查邊界,就和http一樣就行,在頭里寫正文長度,要麼就標記末尾哦

3樓:

應該說這是乙個很簡單很常見的問題,也不太想糾結「粘包」這個術語是否正確,如果將其定義為「HTTP解析器一次讀socket操作獲得的資料可能並不直接對應乙個HTTP message」,那麼應該說這個問題是必然會存在的。

在面向stream的協議基礎上實現乙個面向message的協議,那麼一般來說應用層和底層之間必然存在乙個緩衝區和定時器。於是解析的過程就是,從socket中讀取一次資料放入緩衝區,並檢查目前buffer中內容是否是乙個完整的message,如果是,提交給上層並修改佇列起始位置,如果不是,不提交資料給上層。

這裡存在兩個問題,乙個是緩衝區必然要設定乙個最大上限,另一方面是一般要設定定時器,一段時間內某個連線沒有傳輸足夠資料就斷開連線並清除buffer,否則很容易被惡意請求占用過多記憶體而影響整體穩定性。

具體到HTTP協議,HTTP 1.0無keep alive或HTTP 0.9時,乙個TCP連線只能傳輸乙個HTTP message,所以一次性讀到對端關閉寫即可;有keep alive的情況下,乙個TCP連線可能順序傳過來多個請求,就需要利用content-length等字段,於是文字協議解析部分,從解析整個報文變為解析HTTP頭,並根據HTTP頭中相關字段選擇後續解析策略了,也就是上面提到的緩衝區和定時器的問題。

至於具體的流解析實現,可以採用有狀態實現,即儲存乙個狀態,記錄當前掃瞄到何處,當前狀態如何,之後再有新的資料傳過來,就不必再把前面掃瞄過的資料再掃瞄一遍了;也可以採用無狀態的實現,即不記錄掃瞄到何處,不記錄當前狀態,某次解析後發現不足乙個message,就丟棄當前狀態,待下次讀取資料進佇列尾部,再重頭開始解析。(對於每個message比較小的場景,無狀態版更快,事實上NGINX也是如此實現的)

關於buffer的底層實現,最簡單的版本無疑是演算法與資料結構入門課上的單陣列實現;更詳細的優化版往往是元素為陣列的鍊錶結構,不過具體的效能表現需要經過非常多的測試之後設定引數與策略。

關於HTTP body比較大的情況,一般需要對上層提供流讀寫的API,避免完全將超大報文體放在記憶體中。這樣也可以傳輸超大檔案,而不是 @寸光寸陰 所說的只能用chunked機制。

4樓:錦江老人

誒,這麼多人裝逼。就是很簡單的請求或回應合併在一起, 如果你寫http解析協議當然要考慮這個問題了。

情況就是有。

http協議 1.1 協議最簡單的 GET / \r\n Host :zhihu.

com \r\n\r\n 最簡單命令不過幾十個位元組,如果我們把這些位元組複製20遍,然後一次性傳送過去。伺服器會發生什麼? 它一次會讀取乙個http請求嗎?

並不是,他一次會讀到乙個比較大的包,比如節。這個資料報裡包含了20個請求,解析程式能簡單的把這節當成乙個請求嗎?不可以,所以只有從頭開始不斷讀,當讀到乙個\r\n\r\n的時候檢查一下,前面是乙個完整的http header了嗎?

如果是,看有沒有body,或者是否是truck,所以需要不斷讀,不斷判斷。

結論解析協議是需要判斷邊界問題的,其實基於tcp協議的所有信令都需要解決這個問題。rpc,http 包括2.0,基於流的協議,必須要有辦法判斷邊界。

有人說2.0 不需要,你的幀不也要判斷幀完不完整?

5樓:開始變身

以前在有些人的部落格裡看到粘包。。粘什麼包?tcp負責訊息送到,訊息怎麼處理怎麼分割那是應用層的事。

可以看下http2的單連線復用,哪來的什麼包可粘。。感覺是有些人把傳輸層和應用層混著寫才想出的這種奇葩概念

6樓:

建議把題目改為:

如何正確在TCP流中提取HTTP包,並處理可能的錯誤情況?

因為「粘包」這個詞沒有準確定義,目前的回答都是各說各的。

7樓:沉默無言

看到這個問題,說說自己的看法吧。

首先,TCP協議是流協議,TCP協議本身是沒有包概念的,但是在讀取協議棧buffer(socket)的時候,讀取的是位元組流(package),每次讀取位元組流(package)大小是不一樣的,協議怎麼知道每次讀取都是乙個完整的`業務包`?

這個時候你就要自己設計自己的業務包的大小了,怎麼解析讀取過來的package呢?因為這個package可能是半個、或者多個、多個半的業務包,至於怎麼設計,自己Google一下就知道了,TCP粘包、粘包。

而我們一般說的HTTP協議是基於TCP實現的,因此也要處理每一次讀取TCP協議棧(socket buffer)的`包`(pacage)問題,比如,接收POST資料,讀取協議棧buffer(socket)的package大小是多少?這個包是不是完整的應用層業務邏輯包?怎麼解析?

每一家公司的業務邏輯包都不一樣,所以大小也都不一樣。因此分包、粘包都是業務層的事情,與HTTP協議、TCP協議本身沒有關係。

當然HTTP也提供了乙個chunked,用於分塊傳輸。

但是,作為實現HTTP協議、TCP協議的庫,從socket buffer讀取的資料(因為這個資料可能不是完整業務邏輯包)都會事先快取到應用層的乙個buffer裡面,這個應用層快取buffer的大小一定要有限制!為什麼要限制?如果你不限制,別人攻擊了,會造成記憶體溢位問題!

如果說,應用層快取buffer大小是否限制是考核庫的標準之一,那麼判斷乙個協議庫是不是做的很優雅,就要看這個引數,有沒有提供給庫的呼叫方可設定。

在一些HTTP協議庫中,這個buffer一般都設定死了,defaut大小一般是0.4M(一般的業務包大小,也不會大於這個數了)左右,並且很少有給外界修改這個引數方法,如果你要傳輸大檔案,請使用chunked機制。

因此,那些說HTTP不用分包的,估計也是半懂不懂,不用chunked機制,你試試傳送100M的資料,你能傳輸不?

那些整天說TCP協議是流協議的,不用分包的,你們都是照本宣科吧,TCP協議本身確實沒有包的概念,但是你們有沒有親自實現乙個二進位制協議的?遇到過這種場景麼(讀取socket buffer的資料不是乙個完整的業務包,怎麼處理的問題),就在這類瞎歪歪的,誤人子弟。

因此,基於TCP的協議的,黏包、分包概念指都是自己業務層邏輯包,與協議本身無關。

至於解析自定義協議,可以看看陳碩老師的muduo 網路庫。這個庫確實寫的挺好。

針對你問的問題:一句話總結,不合符HTTP協議請求的快取(到buffer裡面)起來,繼續接收資料,然後再驗證,直到是乙個完整的HTTP請求。這種是乙個完整HTTP請求或應答資料,分了兩次從socket buffer裡面讀取出來。

8樓:嘿-姑娘

如果你解析http協議為什麼不會有粘包?? 比如http 如果是 chunked。那麼我本來伺服器是乙個chunked代表乙個訊息,那麼多個chunked同時達到就出現了你講的粘包了。

TCP是流的HTTP是基於TCP的為什麼不會出現粘包。如果你是工具黨,使用別人寫好的http框架你當然不用考慮,因為別人已經幫你做好了。尤其http 2.

0後是http 真正意義上的全雙工協議了(之前的http協議都是一問一答的 ping pang 協議)這個時候就可以把http 看成和TCP類似的協議。當然要處理粘包和半包的情況。

9樓:

TCP,有個問題要請教你一下,HTTP小姐用誠懇的目光看著TCP先生說道。

請講,TCP先生清了清喉嚨說道。

HTTP小姐說:這個提問者說的粘包是什麼意思?

去台灣讀書是否有風險,是否要考慮政治問題?

碩士準備出國可以來,來之前在大陸買份靠譜的人身保險,要出了啥事台灣不會管你死活的。附上2015年八仙塵爆的新聞截圖,陸生被燒傷都是仰仗保險賠款支付醫藥費的,可悲可嘆! 首先,台灣人不會對大陸人有仇視心態,即便他是南部的深綠人士。在台灣政治和生活離得很遠。其次,台灣人很明白,現在與內地對立沒有好結果。...

待產包要準備多少紙尿褲,是否需要囤貨?

陽光太太 不需要,可以根據B超顯示的寶寶體重來選購NB碼或S碼。一般不超過7斤,選NB碼就可以了。剛出生的寶寶更換紙尿褲會很勤,一般一天會需要6 8片 寶寶頭三個月會長得很快,我家寶貝用了一包不到就換成S碼了,後面再根據寶寶的體重來酌情囤貨。如果是在母嬰店裡做活動預存囤貨,一定要注意這一點 指定的某...

新手是否要考慮之後才按下快門?

楊思陽 必須考慮,但是不按快門對於新手來講完全不知道效果是如何的。現在不是膠卷時代,容錯率大大提高,一下快門也就占用1次快門壽命和幾十MB,而膠卷時代一下快門就是錢。新手到老手必須有按快門的過程,那種不按快門就知道什麼樣子的人是極少數。 雪白的狐狸 當然要考慮好了再拍,你連你要拍什麼都不清楚呢,怎麼...