一鸯隅、 項目背景
? ? ?一個物聯(lián)網(wǎng)項目,公司要求降低硬件成本磅摹,真可謂窮公司練技術滋迈,硬件資源有限制霎奢,最終技術選型使用單片機户誓,因資源受限,硬件sdk中沒有現(xiàn)成的http可使用幕侠,因此帝美,最終嵌軟同學直接在TCP socket基礎上,構造了Http請求頭晤硕,仿造http與物聯(lián)網(wǎng)平臺進行交互悼潭。
? ? 因此庇忌,有意思的事情發(fā)生了,嵌軟同學仿造http的過程如下:
1舰褪、初始化tcp client皆疹,然后構造http請求,通過tcp send發(fā)送http請求占拍,接著recv等待對端的返回略就;
2、收到recv報文之后晃酒,讀取整個response報文表牢,然后轉化為string,從string中匹配content-length字段贝次,從而獲取response的body體大小崔兴。
看似一切正常,而且嵌軟同學之前也這么做過蛔翅,為啥這次就不行了那敲茄,一切都是chunk(這里就不解釋啥是chunk了,不知的同學自行百度吧)搞的鬼山析,有的時候server會使用chunk方式進行數(shù)據(jù)返回折汞,chunk模式下,是可以不存在content-length字段的(嚴格上來說是沒有content-length)盖腿,因此這種情況下爽待,按照上面的流程就跑不通了。
二翩腐、content-length和chunk是如何工作的鸟款?
? ? 這里百度了一些文章,說是chunk和gzip有關茂卦,但是百思不得其解何什,沒有縷出來兩者的關聯(lián)關系,實驗了一些demo等龙,請求和返回頭里都含有gzip的壓縮方式处渣,但是content-lenght字段還是存在,所以蛛砰,索性認為沒有必然聯(lián)系罐栈。
? ? 再繼續(xù)百度了下,說是chunk和keep-alive相關泥畅,看到這我想是因為http1.1支持了連接服用荠诬,因此才支持了chunk,但是并不是說一旦開啟了keep-alive所有交互都是chunk模式,事實自己也寫了個小demo試了下柑贞,確實如此方椎。
?繼續(xù)百度之旅,最后看到chunk和flush函數(shù)有關钧嘶,正常我們server端在返回數(shù)據(jù)的時候棠众,是使用write函數(shù),而write函數(shù)并不是直接給用戶返回數(shù)據(jù)有决,而是先降數(shù)據(jù)寫回緩沖區(qū)摄欲,直到連接close之前,會先將緩沖區(qū)的數(shù)據(jù)buffer發(fā)送過去疮薇,然后close連接胸墙。而flash函數(shù)則是手動將緩沖區(qū)的數(shù)據(jù)發(fā)送到客戶端,然后server端可以繼續(xù)將數(shù)據(jù)寫到緩沖區(qū)按咒,然后再調用flush函數(shù)迟隅,而還是之前的那一個連接(我想這也是之前百度到的一些文章說chunk和keepalive有關的原因吧),這樣收到的傳輸方式就是chunk的方式励七。而我們調用write函數(shù)智袭,然后等到hander結束,close連接之前發(fā)送數(shù)據(jù)這個流程掠抬,也就是我們說的非chunk方式吧(除buff中數(shù)據(jù)超過buff大小的情況)吼野。
三、demo驗證
? ? 這里采用golang代碼進行了過程驗證两波。
1瞳步、使用gin router寫了一個簡單的請求,如下:
????r :=gin.Default()
????r.GET("/ping", func(c *gin.Context) {
????????c.JSON(200, gin.H{
????????????"message":"pong",
? ? ????? })
})
r.Run()
請求結果如下所示:
2腰奋、修改flush發(fā)送數(shù)據(jù)方式单起,如下:
????r :=gin.Default()
????r.GET("/ping", func(c *gin.Context) {
????w := c.Writer
????flusher, ok := w.(http.Flusher)
? ? if !ok {
????????panic("expected http.ResponseWriter to be an http.Flusher")
????}
????fmt.Fprintf(w,string("hello chunk!"))
????flusher.Flush()
? ?})
r.Run()
結果如下圖:
四、總結
? ?1劣坊、通過理論+實驗來看嘀倒,chunk和keepalive有關系,chunk是基于keekalive基礎實現(xiàn)的局冰,但是他們倆者之間并不是必然的關系测蘑。
? ? 2、server端如果不想采取chunk方式回復數(shù)據(jù)康二,以免有些客戶端對chunk支持性不好碳胳,通過server端可以對傳輸方式進行控制,比如通過避免使用flush函數(shù)回復數(shù)據(jù)的方式赠摇。
? ? 3固逗、至于其他語言例如java如何控制傳輸方式浅蚪,后面我們再完善補充藕帜,多謝烫罩。