Android 網(wǎng)絡(luò)協(xié)議全解

** 網(wǎng)絡(luò)分層**
OSI七層模型
OSI七層協(xié)議模型主要是:應(yīng)用層(Application)、表示層(Presentation)淳蔼、會(huì)話層(Session)坷襟、傳輸層(Transport)、網(wǎng)絡(luò)層(Network)配名、數(shù)據(jù)鏈路層(Data Link)啤咽、物理層(Physical)。

TCP/IP五層模型
TCP/IP五層模型:應(yīng)用層(Application)渠脉、傳輸層(Transport)宇整、網(wǎng)絡(luò)層(Network)、數(shù)據(jù)鏈路層(Data Link)芋膘、物理層(Physical)鳞青。(也可以說(shuō)四層,沒(méi)有物理層)

TCP为朋,UDP
TCP和UDP協(xié)議都位于OSI七層模型中的傳輸層臂拓,處于IP協(xié)議的上一層,隸屬于TCP/IP協(xié)議簇

TCP和UDP是傳輸層的兩個(gè)主要協(xié)議习寸,互為補(bǔ)充胶惰,都是用于處理數(shù)據(jù)包。UDP支持無(wú)連接傳輸融涣,是不可靠的童番,但是傳輸性能好;TCP是面向連接的威鹿,可靠性更高剃斧,用得也最多。

TCP協(xié)議
傳輸控制協(xié)議(TCP忽你,Transmission Control Protocol)是一種面向連接的幼东、可靠的、基于字節(jié)流的傳輸層通信協(xié)議科雳。

應(yīng)用層向TCP層發(fā)送用于網(wǎng)間傳輸?shù)母贰⒂?位字節(jié)表示的數(shù)據(jù)流,然后TCP把數(shù)據(jù)流分區(qū)成適當(dāng)長(zhǎng)度的報(bào)文段之后TCP把結(jié)果包傳給IP層糟秘,由它來(lái)通過(guò)網(wǎng)絡(luò)將包傳送給接收端實(shí)體的TCP層简逮。TCP為了保證不發(fā)生丟包,就給每個(gè)包一個(gè)序號(hào)尿赚,同時(shí)序號(hào)也保證了傳送到接收端實(shí)體的包的按序接收散庶。然后接收端實(shí)體對(duì)已成功收到的包發(fā)回一個(gè)相應(yīng)的確認(rèn)(ACK)蕉堰;如果發(fā)送端實(shí)體在合理的往返時(shí)延(RTT)內(nèi)未收到確認(rèn),那么對(duì)應(yīng)的數(shù)據(jù)包就被假設(shè)為已丟失將會(huì)被進(jìn)行重傳悲龟。TCP用一個(gè)校驗(yàn)和函數(shù)來(lái)檢驗(yàn)數(shù)據(jù)是否有錯(cuò)誤屋讶;在發(fā)送和接收時(shí)都要計(jì)算校驗(yàn)和。

TCP的可靠性通過(guò)以下方式來(lái)保證:

超時(shí)重傳:TCP每發(fā)送出一個(gè)報(bào)文段后须教,都會(huì)啟動(dòng)一個(gè)定時(shí)器皿渗,對(duì)目的端傳回的確認(rèn)信息進(jìn)行確認(rèn)計(jì)時(shí),超時(shí)后便重傳轻腺。
確認(rèn)信號(hào):當(dāng)TCP收到一個(gè)來(lái)自TCP的報(bào)文段后乐疆,便會(huì)發(fā)送回一個(gè)確認(rèn)信號(hào)。
檢驗(yàn)和:TCP將始終保持首部和數(shù)據(jù)的檢驗(yàn)和约计,如果收到的報(bào)文段的檢驗(yàn)和有差錯(cuò)诀拭,便將其丟棄迁筛,希望發(fā)送端超時(shí)重傳煤蚌。
重新排序:由于IP數(shù)據(jù)報(bào)的達(dá)到可能失序,因此TCP將會(huì)對(duì)數(shù)據(jù)進(jìn)行重新排序细卧,以正確的順序交給應(yīng)用層尉桩。
丟棄重復(fù):由于IP數(shù)據(jù)報(bào)有可能重復(fù),因此TCP將會(huì)丟棄重復(fù)的數(shù)據(jù)贪庙。
流量控制:TCP連接的兩端都有固定大小的緩沖區(qū)空間蜘犁,TCP接受端只允許對(duì)端發(fā)送本端緩沖區(qū)能容納的數(shù)據(jù)。
TCP提供流量控制止邮。在雙方進(jìn)行交互時(shí)这橙,會(huì)彼此通知自己目前接收緩沖區(qū)最多可以接收的數(shù)據(jù)量(通告窗口),以此確保發(fā)送方發(fā)送的數(shù)據(jù)不會(huì)溢出接收緩沖區(qū)导披。


1687071409220.jpg

TCP頭部消息


image.png

TCP數(shù)據(jù)包主要包括:

SYN包:請(qǐng)求建立連接的數(shù)據(jù)包
ACK包:回應(yīng)數(shù)據(jù)包屈扎,表示接收到了對(duì)方的某個(gè)數(shù)據(jù)包
PSH包:正常數(shù)據(jù)包
FIN包:通訊結(jié)束包
RST包: 重置連接
導(dǎo)致TCP協(xié)議發(fā)送RST包的原因:
1)SYN 數(shù)據(jù)段指定的目的端口處沒(méi)有接收進(jìn)程在等待。
2)TCP協(xié)議想放棄一個(gè)已經(jīng)存在的連接撩匕。
3)TCP接收到一個(gè)數(shù)據(jù)段鹰晨,但是這個(gè)數(shù)據(jù)段所標(biāo)識(shí)的連接不存在。
源止毕、目標(biāo)端口號(hào)字段:占16比特模蜡。TCP協(xié)議通過(guò)使用”端口”來(lái)標(biāo)識(shí)源端和目標(biāo)端的應(yīng)用進(jìn)程。端口號(hào)可以使用0到65535之間的任何數(shù)字扁凛。在收到服務(wù)請(qǐng)求時(shí)忍疾,操作系統(tǒng)動(dòng)態(tài)地為客戶端的應(yīng)用程序分配端口號(hào)。在服務(wù)器端谨朝,每種服務(wù)在”眾所周知的端口”(Well-Know Port)為用戶提供服務(wù)卤妒。

順序號(hào)字段:占32比特丸边。用來(lái)標(biāo)識(shí)從TCP源端向TCP目標(biāo)端發(fā)送的數(shù)據(jù)字節(jié)流,它表示在這個(gè)報(bào)文段中的第一個(gè)數(shù)據(jù)字節(jié)荚孵。

確認(rèn)號(hào)字段:占32比特妹窖。只有ACK標(biāo)志為1時(shí),確認(rèn)號(hào)字段才有效收叶。它包含目標(biāo)端所期望收到源端的下一個(gè)數(shù)據(jù)字節(jié)骄呼。

頭部長(zhǎng)度字段:占4比特。給出頭部占32比特的數(shù)目判没。沒(méi)有任何選項(xiàng)字段的TCP頭部長(zhǎng)度為20字節(jié)蜓萄;最多可以有60字節(jié)的TCP頭部。

標(biāo)志位字段(U澄峰、A嫉沽、P、R俏竞、S绸硕、F):占6比特。各比特的含義如下:

◆URG:緊急指針(urgent pointer)有效魂毁。
◆ACK:為1時(shí)玻佩,確認(rèn)序號(hào)有效。  
◆PSH:為1時(shí)席楚,接收方應(yīng)該盡快將這個(gè)報(bào)文段交給應(yīng)用層咬崔。  
◆RST:為1時(shí),重建連接烦秩。
◆SYN:為1時(shí)垮斯,同步程序,發(fā)起一個(gè)連接只祠。  
◆FIN:為1時(shí)兜蠕,發(fā)送端完成任務(wù),釋放一個(gè)連接铆农。

窗口大小字段:占16比特牺氨。此字段用來(lái)進(jìn)行流量控制。單位為字節(jié)數(shù)墩剖,這個(gè)值是本機(jī)期望一次接收的字節(jié)數(shù)猴凹。

TCP校驗(yàn)和字段:占16比特。對(duì)整個(gè)TCP報(bào)文段岭皂,即TCP頭部和TCP數(shù)據(jù)進(jìn)行校驗(yàn)和計(jì)算郊霎,并由目標(biāo)端進(jìn)行驗(yàn)證。

緊急指針字段:占16比特爷绘。它是一個(gè)偏移量书劝,和序號(hào)字段中的值相加表示緊急數(shù)據(jù)最后一個(gè)字節(jié)的序號(hào)进倍。

選項(xiàng)字段:占32比特」憾裕可能包括”窗口擴(kuò)大因子”猾昆、”時(shí)間戳”等選項(xiàng)。

TCP建立三次連接的過(guò)程(三次握手)
TCP是因特網(wǎng)中的傳輸層協(xié)議骡苞,使用三次握手協(xié)議建立連接垂蜗。當(dāng)主動(dòng)方發(fā)出SYN連接請(qǐng)求后,等待對(duì)方回答 SYN + ACK 解幽,并最終對(duì)對(duì)方的 SYN 執(zhí)行 ACK 確認(rèn)贴见。這種建立連接的方法可以防止產(chǎn)生錯(cuò)誤的連接,TCP 使用的流量控制協(xié)議是可變大小的滑動(dòng)窗口協(xié)議躲株。

TCP三次握手的過(guò)程如下:


image.png

客戶端發(fā)送 SYN(SEQ=x)報(bào)文給服務(wù)器端片部,進(jìn)入 SYN_SEND 狀態(tài)。
服務(wù)器端收到 SYN 報(bào)文霜定,回應(yīng)一個(gè) SYN (SEQ=y)ACK(ACK=x+1)報(bào)文档悠,進(jìn)入 SYN_RECV 狀態(tài)。
客戶端收到服務(wù)器端的 SYN 報(bào)文然爆,回應(yīng)一個(gè) ACK(ACK=y+1)報(bào)文站粟,進(jìn)入 Established 狀態(tài)黍图。
三次握手完成曾雕,TCP客戶端和服務(wù)器端成功地建立連接,可以開(kāi)始傳輸數(shù)據(jù)了助被。

三次握手可以簡(jiǎn)單理解為A剖张、B兩人開(kāi)始連麥開(kāi)黑:

A:聽(tīng)到嗎? (第一次握手)
B:聽(tīng)得到揩环,你能聽(tīng)到我的聲音嗎搔弄? (第二次握手)
A:能聽(tīng)到。 (第三次握手)

ok丰滑,麥沒(méi)問(wèn)題顾犹,開(kāi)始游戲

TCP終止連接過(guò)程(四次揮手)
客戶端進(jìn)程發(fā)出連接釋放報(bào)文,并且停止發(fā)送數(shù)據(jù)褒墨。釋放數(shù)據(jù)報(bào)文首部炫刷,F(xiàn)IN=1,其序列號(hào)為seq=u(等于前面已經(jīng)傳送過(guò)來(lái)的數(shù)據(jù)的最后一個(gè)字節(jié)的序號(hào)加1)郁妈,此時(shí)浑玛,客戶端進(jìn)入FIN-WAIT-1(終止等待1)狀態(tài)。TCP規(guī)定噩咪,F(xiàn)IN報(bào)文段即使不攜帶數(shù)據(jù)顾彰,也要消耗一個(gè)序號(hào)。
服務(wù)器收到連接釋放報(bào)文,發(fā)出確認(rèn)報(bào)文拿霉,ACK=1同云,ack=u+1,并且?guī)献约旱男蛄刑?hào)seq=v厕隧,此時(shí)拆又,服務(wù)端就進(jìn)入了CLOSE-WAIT(關(guān)閉等待)狀態(tài)。TCP服務(wù)器通知高層的應(yīng)用進(jìn)程栏账,客戶端向服務(wù)器的方向就釋放了帖族,這時(shí)候處于半關(guān)閉狀態(tài),即客戶端已經(jīng)沒(méi)有數(shù)據(jù)要發(fā)送了挡爵,但是服務(wù)器若發(fā)送數(shù)據(jù)竖般,客戶端依然要接受。這個(gè)狀態(tài)還要持續(xù)一段時(shí)間茶鹃,也就是整個(gè)CLOSE-WAIT狀態(tài)持續(xù)的時(shí)間涣雕。客戶端收到服務(wù)器的確認(rèn)請(qǐng)求后闭翩,此時(shí)挣郭,客戶端就進(jìn)入FIN-WAIT-2(終止等待2)狀態(tài),等待服務(wù)器發(fā)送連接釋放報(bào)文(在這之前還需要接受服務(wù)器發(fā)送的最后的數(shù)據(jù))疗韵。
服務(wù)器將最后的數(shù)據(jù)發(fā)送完畢后兑障,就向客戶端發(fā)送連接釋放報(bào)文,F(xiàn)IN=1蕉汪,ack=u+1流译,由于在半關(guān)閉狀態(tài),服務(wù)器很可能又發(fā)送了一些數(shù)據(jù)者疤,假定此時(shí)的序列號(hào)為seq=w福澡,此時(shí),服務(wù)器就進(jìn)入了LAST-ACK(最后確認(rèn))狀態(tài)驹马,等待客戶端的確認(rèn)革砸。客戶端收到服務(wù)器的連接釋放報(bào)文后糯累,必須發(fā)出確認(rèn)算利,ACK=1,ack=w+1寇蚊,而自己的序列號(hào)是seq=u+1笔时,此時(shí),客戶端就進(jìn)入了TIME-WAIT(時(shí)間等待)狀態(tài)仗岸。注意此時(shí)TCP連接還沒(méi)有釋放允耿,必須經(jīng)過(guò)2?MSL(最長(zhǎng)報(bào)文段壽命)的時(shí)間后借笙,當(dāng)客戶端撤銷相應(yīng)的TCB后,才進(jìn)入CLOSED狀態(tài)较锡。(等待 2MSL 的真正目的是為了避免前后兩個(gè)使用相同四元組的連接中的前一個(gè)連接的報(bào)文干擾后一個(gè)連接业稼,所以讓TIME_WAIT狀態(tài)保持時(shí)間?夠長(zhǎng)(2MSL),連接相應(yīng)?向的上的TCP報(bào)?要么完全響應(yīng)完畢蚂蕴,要么被丟棄低散。建?第?個(gè)連接的時(shí)候,不會(huì)混淆骡楼。就是為了讓此次 TCP 連接中的所有報(bào)文在網(wǎng)絡(luò)中消失熔号。)
.
服務(wù)器只要收到了客戶端發(fā)出的確認(rèn),立即進(jìn)入CLOSED狀態(tài)鸟整。同樣引镊,撤銷TCB后,就結(jié)束了這次的TCP連接篮条〉芡罚可以看到,服務(wù)器結(jié)束TCP連接的時(shí)間要比客戶端早一些涉茧。


image.png

第一次揮手:客戶端發(fā)送報(bào)文告訴服務(wù)器沒(méi)有數(shù)據(jù)要發(fā)送了
第二次揮手:服務(wù)端收到赴恨,再發(fā)送給客戶端告訴它我收到了
第三次揮手:服務(wù)端向客戶端發(fā)送報(bào)文,請(qǐng)求關(guān)閉連接
第四次揮手:客戶端收到關(guān)閉連接的請(qǐng)求伴栓,向服務(wù)端發(fā)送報(bào)文伦连,服務(wù)端關(guān)閉連接

四次揮手可以簡(jiǎn)單地理解為A、B兩人結(jié)束對(duì)話:
A:我已經(jīng)講完了挣饥。 (第一次揮手)
B:知道啦除师。 (第二次揮手)
B:但是我還沒(méi)講完,我跟你講哦%#¥#¥%#… (A在聽(tīng)B講完)
B:我講完啦扔枫。 (第三次揮手)
A:收到。 (第四次揮手)

然后各回各家锹安,各找各媽

另一篇文章說(shuō)法:
三次握手與四次揮手

第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器短荐,并進(jìn)入SYN_SEND(郵寄)狀態(tài),等待服務(wù)器確認(rèn)叹哭;

第二次握手:服務(wù)器收到syn包忍宋,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k)风罩,即SYN+ACK包糠排,此時(shí)服務(wù)器進(jìn)入SYN_RECV(記錄)狀態(tài);

第三次握手:客戶端收到服務(wù)器的SYN+ACK包超升,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1)入宦,此包發(fā)送完畢哺徊,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手乾闰。

握手過(guò)程中傳送的包里不包含數(shù)據(jù)落追,三次握手完畢后,客戶端與服務(wù)器才正式開(kāi)始傳送數(shù)據(jù)涯肩。理想狀態(tài)下轿钠,TCP連接一旦建立,在通信雙方中的任何一方主動(dòng)關(guān)閉連接之前病苗,TCP 連接都將被一直保持下去疗垛。斷開(kāi)連接時(shí)服務(wù)器和客戶端均可以主動(dòng)發(fā)起斷開(kāi)TCP連接的請(qǐng)求,斷開(kāi)過(guò)程需要經(jīng)過(guò)“四次揮手”

第一次揮手:客戶端發(fā)送報(bào)文告訴服務(wù)器沒(méi)有數(shù)據(jù)要發(fā)送了

第二次揮手:服務(wù)端收到硫朦,再發(fā)送給客戶端告訴它我收到了

第三次揮手:服務(wù)端向客戶端發(fā)送報(bào)文继谚,請(qǐng)求關(guān)閉連接

第四次揮手:客戶端收到關(guān)閉連接的請(qǐng)求,向服務(wù)端發(fā)送報(bào)文阵幸,服務(wù)端關(guān)閉連接

TCP為什么三次握手不是兩次握手花履,為什么兩次握手不安全

為了實(shí)現(xiàn)可靠數(shù)據(jù)傳輸, TCP 協(xié)議的通信雙方挚赊, 都必須維護(hù)一個(gè)序列號(hào)诡壁, 以標(biāo)識(shí)發(fā)送出去的數(shù)據(jù)包中, 哪些是已經(jīng)被對(duì)方收到的荠割。 三次握手的過(guò)程即是通信雙方相互告知序列號(hào)起始值妹卿, 并確認(rèn)對(duì)方已經(jīng)收到了序列號(hào)起始值的必經(jīng)步驟

如果只是兩次握手, 至多只有連接發(fā)起方的起始序列號(hào)能被確認(rèn)蔑鹦, 另一方選擇的序列號(hào)則得不到確認(rèn)

TCP數(shù)據(jù)的發(fā)送
TCP分組: TCP是可靠傳輸協(xié)議夺克,通過(guò)超時(shí)與重傳機(jī)制,來(lái)保證收到的數(shù)據(jù)是完整的嚎朽。因?yàn)門CP是可靠傳輸協(xié)議铺纽,如果要傳輸?shù)臄?shù)據(jù)大于 1480 - 20(tcp頭部) =1460Byte時(shí),在ip層被分片哟忍,而ip層分片會(huì)導(dǎo)致狡门,如果其中的某一個(gè)分片丟失,因?yàn)閠cp層不知道哪個(gè)ip數(shù)據(jù)片丟失锅很,所以就需要重傳整個(gè)數(shù)據(jù)段其馏,這樣就造成了很大空間和時(shí)間資源的浪費(fèi),為了解決這個(gè)問(wèn)題爆安,就有了tcp分組和MSS(最長(zhǎng)報(bào)文大信迅础)概念,利用tcp三次握手建立鏈接的過(guò)程,交互各自的MTU(最大傳輸單元)褐奥,然后用小的那個(gè)MTU-20-20咖耘, 得到MSS,這樣就避免在ip層被分片抖僵。

在TCP連接建立后鲤看, TCP便進(jìn)入了數(shù)據(jù)傳輸?shù)臓顟B(tài), 數(shù)據(jù)發(fā)送的步驟如下圖所示耍群,具體為:


image.png

在發(fā)送數(shù)據(jù)時(shí)义桂, 發(fā)送方對(duì)分組數(shù)據(jù)進(jìn)行封裝, 這里將該分組稱為F(x)蹈垢。 設(shè)置F(x)分組的SEQ為其攜帶的數(shù)據(jù)的首字節(jié)的序號(hào)慷吊,這里假設(shè)其為100;ACK設(shè)置為發(fā)送方上一次接收到的分組的SEQ+數(shù)據(jù)長(zhǎng)度+1曹抬,這里假設(shè)其為1溉瓶。
接收方接收到該分組后, 會(huì)向發(fā)送方發(fā)送一個(gè)確認(rèn)報(bào)文谤民, 這里將其稱為F(x+1)堰酿。 該報(bào)文的ACK字段為F(x).SEQ+LEN,即希望接收的下一個(gè)分組的序列號(hào)张足,這里為100+60=160(注意該分組的最后一個(gè)字節(jié)的序列號(hào)為159)触创。
在上述傳輸中, 若F(x+1)無(wú)法順利到達(dá)或者延遲到達(dá)發(fā)送方为牍, 則會(huì)導(dǎo)致F(x)的重發(fā)哼绑。 這種情況可能導(dǎo)致接收方收到多個(gè)F(x)的副本,接收方通過(guò)SEQ來(lái)判斷是否接收過(guò)該分組碉咆, 并丟棄重復(fù)的分組抖韩。

接收端在收到數(shù)據(jù)包后不立馬進(jìn)行ACK數(shù)據(jù)包的發(fā)送,而是等待一定的時(shí)間疫铜,并統(tǒng)一對(duì)收到的多個(gè)數(shù)據(jù)包進(jìn)行ACK茂浮,這種方法稱為延遲確認(rèn)。延遲確認(rèn)能夠減少數(shù)據(jù)包的發(fā)送块攒,節(jié)約資源励稳。當(dāng)接收隊(duì)列中存在失序分組時(shí),延遲確認(rèn)將不起作用:收到任意數(shù)據(jù)包時(shí)都將立馬進(jìn)行ACK囱井。

分組窗口和滑動(dòng)窗口
在上述的TCP分組發(fā)送過(guò)程中, 上一個(gè)分組發(fā)送成功并得到確認(rèn)后趣避, 下一個(gè)分組才能發(fā)送庞呕, 而這中間的“等待”會(huì)造成效率的降低。 如果同時(shí)允許多個(gè)分組進(jìn)入網(wǎng)絡(luò)又會(huì)引發(fā)一系列的問(wèn)題。 為解決這一些列的問(wèn)題住练, 滑動(dòng)窗口的概念被提出地啰。

建立TCP的兩端都維護(hù)著一個(gè)發(fā)送窗口結(jié)構(gòu)和接收窗口結(jié)構(gòu)。發(fā)送窗口指的是將發(fā)送的TCP分組按照其序列號(hào)順序放置到一個(gè)窗口中讲逛,窗口左邊為已確認(rèn)的分組亏吝,右邊為待發(fā)送的分組,窗口里為已發(fā)送但還未確認(rèn)的分組盏混,如下圖所示蔚鸥。圖中,2许赃、3為已確認(rèn)的分組止喷,10、11為待發(fā)送的分組混聊,4-9為窗口中的已發(fā)送待確認(rèn)的分組弹谁。


image.png

此時(shí)當(dāng)我們收到4號(hào)分組的ACK,10號(hào)分組會(huì)被發(fā)送從而進(jìn)入窗口句喜,4號(hào)分組得到確認(rèn)從而退出窗口预愤,這個(gè)過(guò)程仿佛窗口往右滑動(dòng)了一段,因此稱為滑動(dòng)窗口咳胃。

接收窗口的實(shí)現(xiàn)邏輯與發(fā)送窗口類似植康,這里不再贅述。

在分組傳輸過(guò)程中拙绊,窗口的大小是動(dòng)態(tài)變化的向图,接收方會(huì)通過(guò)窗口通告發(fā)送分組告知發(fā)送方采用多大的窗口大小(簡(jiǎn)稱為:目標(biāo)窗口大斜昊Α)榄攀。當(dāng)目標(biāo)窗口大小小于當(dāng)前窗口大小時(shí),發(fā)送窗口的右邊界不動(dòng)金句,左邊界右移檩赢,實(shí)現(xiàn)窗口的“縮小”;當(dāng)目標(biāo)窗口大小大于當(dāng)前窗口大小時(shí)违寞,發(fā)送窗口的左邊界不動(dòng)贞瞒,右邊界右移,實(shí)現(xiàn)窗口的“放大”趁曼。

在數(shù)據(jù)發(fā)送過(guò)程中军浆,當(dāng)接收方跟不上發(fā)送方的速度時(shí),需要告知發(fā)送方慢下來(lái)挡闰,這稱為流量控制乒融。使用滑動(dòng)窗口能夠很好的進(jìn)行流量控制:接收方通過(guò)通告較小的窗口大小來(lái)降低發(fā)送方的發(fā)送速度掰盘。當(dāng)接收方忙碌時(shí),可以將目標(biāo)窗口大小設(shè)置為0赞季,從而使發(fā)送方停止發(fā)送愧捕。此時(shí)發(fā)送方將定期向接收方發(fā)送探測(cè)報(bào)文(keep-alive)來(lái)查看接收方窗口的狀態(tài),一旦查詢到目標(biāo)窗口大小為非零值申钩,將繼續(xù)進(jìn)行分組的發(fā)送次绘。

UDP
UDP協(xié)議
UDP協(xié)議全稱是用戶數(shù)據(jù)報(bào)協(xié)議,在網(wǎng)絡(luò)中它與TCP協(xié)議一樣用于處理數(shù)據(jù)包撒遣,是一種無(wú)連接的協(xié)議邮偎。UDP有不提供數(shù)據(jù)包分組、組裝和不能對(duì)數(shù)據(jù)包進(jìn)行排序的缺點(diǎn)愉舔,也就是說(shuō)钢猛,當(dāng)報(bào)文發(fā)送之后,是無(wú)法得知其是否安全完整到達(dá)的轩缤。

UDP不屬于連接型協(xié)議命迈,因而具有資源消耗小,處理速度快的優(yōu)點(diǎn)火的,所以通常音頻壶愤、視頻和普通數(shù)據(jù)在傳送時(shí)使用UDP較多,因?yàn)樗鼈兗词古紶杹G失一兩個(gè)數(shù)據(jù)包馏鹤,也不會(huì)對(duì)接收結(jié)果產(chǎn)生太大影響征椒。比如我們聊天用的QQ就是使用的UDP協(xié)議。

UDP應(yīng)用場(chǎng)景:
1.面向數(shù)據(jù)報(bào)方式
2.網(wǎng)絡(luò)數(shù)據(jù)大多為短消息
3.擁有大量Client
4.對(duì)數(shù)據(jù)安全性無(wú)特殊要求
5.網(wǎng)絡(luò)負(fù)擔(dān)非常重湃累,但對(duì)響應(yīng)速度要求高

TCP傳輸?shù)目煽啃杂蓱?yīng)用層負(fù)責(zé)勃救,由應(yīng)用程序根據(jù)需要提供報(bào)文ACK機(jī)制、重傳機(jī)制治力、序號(hào)機(jī)制蒙秒、重排機(jī)制和窗口機(jī)制。也可以使用RUDP實(shí)現(xiàn)宵统。

原文鏈接:https://blog.csdn.net/qq_24125575/article/details/105531656

為什么TCP是可靠的晕讲,UDP是不可靠的?為什么UDP比TCP快?

TCP/IP協(xié)議擁有三次握手雙向機(jī)制,這一機(jī)制保證校驗(yàn)了數(shù)據(jù)马澈,保證了他的可靠性瓢省。

UDP就沒(méi)有了,udp信息發(fā)出后,不驗(yàn)證是否到達(dá)對(duì)方,所以不可靠痊班。

TCP和UDP的區(qū)別


image.png

1勤婚、TCP面向連接(如打電話要先撥號(hào)建立連接);UDP是無(wú)連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接

2涤伐、TCP提供可靠的服務(wù)蛔六。也就是說(shuō)荆永,通過(guò)TCP連接傳送的數(shù)據(jù)废亭,無(wú)差錯(cuò)国章,不丟失,不重復(fù)豆村,且按序到達(dá); UDP盡最大努力交付液兽,即不保證可靠交付

3、TCP面向字節(jié)流掌动,實(shí)際上是TCP把數(shù)據(jù)看成一連串無(wú)結(jié)構(gòu)的字節(jié)流;UDP是面向報(bào)文的

UDP沒(méi)有擁塞控制四啰,因此網(wǎng)絡(luò)出現(xiàn)擁塞不會(huì)使源主機(jī)的發(fā)送速率降低(對(duì)實(shí)時(shí)應(yīng)用很有用,如IP電話粗恢,實(shí)時(shí)視頻會(huì)議等)

4柑晒、每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對(duì)一,一對(duì)多眷射,多對(duì)一和多對(duì)多的交互通信

5匙赞、TCP首部開(kāi)銷20字節(jié);UDP的首部開(kāi)銷小,只有8個(gè)字節(jié)

6妖碉、TCP的邏輯通信信道是全雙工的可靠信道涌庭,UDP則是不可靠信道

TCP粘包、分包的解決辦法

粘包的原因:

(1)發(fā)送方引起的粘包是由TCP協(xié)議本身造成的欧宜,TCP為提高傳輸效率坐榆,發(fā)送方往往要收集到足夠多的數(shù)據(jù)后才發(fā)送一包數(shù)據(jù)。若連續(xù)幾次發(fā)送的數(shù)據(jù)都很少冗茸,通常TCP會(huì)根據(jù)優(yōu)化算法把這些數(shù)據(jù)合成一包后一次發(fā)送出去席镀,這樣接收方就收到了粘包數(shù)據(jù)。

(2)接收方引起的粘包是由于接收方用戶進(jìn)程不及時(shí)接收數(shù)據(jù)夏漱,從而導(dǎo)致粘包現(xiàn)象豪诲。這是因?yàn)榻邮辗较劝咽盏降臄?shù)據(jù)放在系統(tǒng)接收緩沖區(qū),用戶進(jìn)程從該緩沖區(qū)取數(shù)據(jù)麻蹋,若下一包數(shù)據(jù)到達(dá)時(shí)前一包數(shù)據(jù)尚未被用戶進(jìn)程取走跛溉,則下一包數(shù)據(jù)放到系統(tǒng)接收緩沖區(qū)時(shí)就接到前一包數(shù)據(jù)之后,而用戶進(jìn)程根據(jù)預(yù)先設(shè)定的緩沖區(qū)大小從系統(tǒng)接收緩沖區(qū)取數(shù)據(jù)扮授,這樣就一次取到了多包數(shù)據(jù)芳室。

粘包的解決辦法————封包:

封包就是給一段數(shù)據(jù)加上包頭,這樣一來(lái)數(shù)據(jù)包就分為包頭和包體兩部分內(nèi)容了。包頭其實(shí)上是個(gè)大小固定的結(jié)構(gòu)體刹勃,其中有個(gè)結(jié)構(gòu)體成員變量表示包體的長(zhǎng)度堪侯,這是個(gè)很重要的變量,其他的結(jié)構(gòu)體成員可根據(jù)需要自己定義荔仁。根據(jù)包頭長(zhǎng)度固定以及包頭中含有包體長(zhǎng)度的變量就能正確的拆分出一個(gè)完整的數(shù)據(jù)包伍宦。

拆包:

根據(jù)封包的包頭規(guī)則解析出每一個(gè)完整的數(shù)據(jù)包诬乞,然后做相應(yīng)的業(yè)務(wù)處理瘤礁。

UDP分包發(fā)送和接收方重組數(shù)據(jù)包

分包:

分包發(fā)送(封裝包的首部,包括包的大小、類型窗宇、序號(hào)撵枢、數(shù)量等)

1池颈、在客戶端將你要發(fā)送的內(nèi)容(文件什么的都可以)分塊贩毕,每塊內(nèi)容進(jìn)行編號(hào),然后發(fā)送亥啦;

2炭剪、服務(wù)端在接收到你的分塊數(shù)據(jù)以后,根據(jù)你的客戶端數(shù)據(jù)類容的編號(hào)重新組裝翔脱;

3奴拦、一般我們?cè)诎l(fā)送數(shù)據(jù)的時(shí)候,盡量采用比較小的數(shù)據(jù)塊的方式(我的都沒(méi)有超過(guò)1024的)届吁,數(shù)據(jù)塊太大的話容易出現(xiàn)發(fā)送和接收的數(shù)據(jù)時(shí)間長(zhǎng)错妖,匹配出問(wèn)題。

組包:

假設(shè)一個(gè)端口只接收固定一個(gè)對(duì)方數(shù)據(jù)源,這樣瓷产,收到一個(gè)數(shù)據(jù)包放到緩沖里站玄,然后在緩沖里根據(jù)幀的序號(hào)排序(每一幀的大序號(hào)是相同的,自己可以給每一個(gè)小片加上小序號(hào),包頭里可以加上本次數(shù)據(jù)幀一共分多少片濒旦,收到一片就統(tǒng)計(jì)一下株旷,判斷是否收齊)。 當(dāng)收齊后尔邓,這個(gè)幀去掉包頭回調(diào)給上層晾剖。當(dāng)在一定時(shí)間內(nèi)該幀數(shù)據(jù)還沒(méi)有收齊,就說(shuō)明傳輸過(guò)程有丟包了梯嗽,把已收到的都丟掉就可以齿尽。

當(dāng)上層的應(yīng)該收到回調(diào)的數(shù)據(jù)后,可以進(jìn)行解碼播放灯节。不過(guò)在解碼之前循头,先判斷一下幀序列是否連續(xù)。做為視頻數(shù)據(jù)炎疆,

如果中間有缺少的卡骂,就把這一序列都丟掉,直到下一個(gè)I幀形入。每個(gè)幀的序號(hào)全跨,最好收發(fā)之間協(xié)商好,在發(fā)送的時(shí)候帶上亿遂。

Tcp/ip協(xié)議
定義
TCP/IP(Transmission Control Protocol/Internet Protocol浓若,傳輸控制協(xié)議/網(wǎng)際協(xié)議)是指能夠在多個(gè)不同網(wǎng)絡(luò)間實(shí)現(xiàn)信息傳輸?shù)膮f(xié)議簇渺杉。TCP/IP協(xié)議不僅僅指的是TCP 和IP兩個(gè)協(xié)議,而是指一個(gè)由FTP挪钓、SMTP是越、TCP、UDP诵原、IP等協(xié)議構(gòu)成的協(xié)議簇英妓, 只是因?yàn)樵赥CP/IP協(xié)議中TCP協(xié)議和IP協(xié)議最具代表性,所以被稱為TCP/IP協(xié)議绍赛。

簡(jiǎn)介
TCP/IP傳輸協(xié)議,即傳輸控制/網(wǎng)絡(luò)協(xié)議辑畦,也叫作網(wǎng)絡(luò)通訊協(xié)議吗蚌。它是在網(wǎng)絡(luò)的使用中的最基本的通信協(xié)議。TCP/IP傳輸協(xié)議對(duì)互聯(lián)網(wǎng)中各部分進(jìn)行通信的標(biāo)準(zhǔn)和方法進(jìn)行了規(guī)定纯出。并且蚯妇,TCP/IP傳輸協(xié)議是保證網(wǎng)絡(luò)數(shù)據(jù)信息及時(shí)、完整傳輸?shù)膬蓚€(gè)重要的協(xié)議暂筝。TCP/IP傳輸協(xié)議是嚴(yán)格來(lái)說(shuō)是一個(gè)四層的體系結(jié)構(gòu)箩言,應(yīng)用層、傳輸層焕襟、網(wǎng)絡(luò)層和數(shù)據(jù)鏈路層都包含其中陨收。

TCP/IP協(xié)議是Internet最基本的協(xié)議,其中應(yīng)用層的主要協(xié)議有Telnet、FTP鸵赖、SMTP等务漩,是用來(lái)接收來(lái)自傳輸層的數(shù)據(jù)或者按不同應(yīng)用要求與方式將數(shù)據(jù)傳輸至傳輸層;傳輸層的主要協(xié)議有UDP它褪、TCP饵骨,是使用者使用平臺(tái)和計(jì)算機(jī)信息網(wǎng)內(nèi)部數(shù)據(jù)結(jié)合的通道,可以實(shí)現(xiàn)數(shù)據(jù)傳輸與數(shù)據(jù)共享茫打;網(wǎng)絡(luò)層的主要協(xié)議有ICMP居触、IP、IGMP老赤,主要負(fù)責(zé)網(wǎng)絡(luò)中數(shù)據(jù)包的傳送等轮洋;而網(wǎng)絡(luò)訪問(wèn)層,也叫網(wǎng)路接口層或數(shù)據(jù)鏈路層诗越,主要協(xié)議有ARP砖瞧、RARP,主要功能是提供鏈路管理錯(cuò)誤檢測(cè)嚷狞、對(duì)不同通信媒介有關(guān)信息細(xì)節(jié)問(wèn)題進(jìn)行有效處理等块促。

TCP/IP模型與OSI模型各層的對(duì)照關(guān)系:


image.png

image.png

數(shù)據(jù)封裝
TCP/IP協(xié)議族按照層次由上到下荣堰,層層包裝。最上面的是應(yīng)用層竭翠,這里面有http振坚,ftp,等等我們熟悉的協(xié)議。而第二層則是傳輸層斋扰,著名的TCP和UDP協(xié)議就在這個(gè)層次渡八。第三層是網(wǎng)絡(luò)層,IP協(xié)議就在這里传货,它負(fù)責(zé)對(duì)數(shù)據(jù)加上IP地址和其他的數(shù)據(jù)以確定傳輸?shù)哪繕?biāo)屎鳍。第四層是數(shù)據(jù)鏈路層,這個(gè)層次為待傳送的數(shù)據(jù)加入一個(gè)以太網(wǎng)協(xié)議頭问裕,并進(jìn)行CRC編碼逮壁,為最后的數(shù)據(jù)傳輸做準(zhǔn)備。


image.png

數(shù)據(jù)鏈路層
物理層負(fù)責(zé)0粮宛、1比特流與物理設(shè)備電壓高低窥淆、光的閃滅之間的互換。 數(shù)據(jù)鏈路層負(fù)責(zé)將0巍杈、1序列劃分為數(shù)據(jù)幀從一個(gè)節(jié)點(diǎn)傳輸?shù)脚R近的另一個(gè)節(jié)點(diǎn),這些節(jié)點(diǎn)是通過(guò)MAC來(lái)唯一標(biāo)識(shí)的(MAC,物理地址忧饭,一個(gè)主機(jī)會(huì)有一個(gè)MAC地址)。

封裝成幀: 把網(wǎng)絡(luò)層數(shù)據(jù)包加頭和尾筷畦,封裝成幀,幀頭中包括源MAC地址和目的MAC地址词裤。

透明傳輸:零比特填充、轉(zhuǎn)義字符汁咏。

可靠傳輸: 在出錯(cuò)率很低的鏈路上很少用亚斋,但是無(wú)線鏈路WLAN會(huì)保證可靠傳輸。

差錯(cuò)檢測(cè)(CRC):接收者檢測(cè)錯(cuò)誤,如果發(fā)現(xiàn)差錯(cuò)攘滩,丟棄該幀帅刊。

網(wǎng)絡(luò)層
1、IP協(xié)議
IP協(xié)議是TCP/IP協(xié)議的核心漂问,所有的TCP赖瞒,UDP,IMCP蚤假,IGMP的數(shù)據(jù)都以IP數(shù)據(jù)格式傳輸栏饮。要注意的是,IP不是可靠的協(xié)議磷仰,這是說(shuō)袍嬉,IP協(xié)議沒(méi)有提供一種數(shù)據(jù)未傳達(dá)以后的處理機(jī)制,這被認(rèn)為是上層協(xié)議:TCP或UDP要做的事情。

IP所提供的服務(wù)大致可歸納為兩類:

IP信息包的傳送伺通。
IP信息包的分割與重組箍土。
1.1、IP信息包傳送
IP是網(wǎng)絡(luò)之間信息傳送的協(xié)議罐监,可將IP信息包從源設(shè)備(例如用戶的計(jì)算機(jī))傳送到目的設(shè)備(例如某部門的www服務(wù)器)吴藻。為了達(dá)到這樣的目的,IP必須依賴IP地址與IP路由器兩種機(jī)制來(lái)實(shí)現(xiàn)弓柱。

1.1.1沟堡、IP地址
IP規(guī)定網(wǎng)絡(luò)上所有的設(shè)備都必須有一個(gè)獨(dú)一無(wú)二的IP地址,就好比是郵件上都必須注明收件人地址矢空,郵遞員才能將郵件送到航罗。同理,每個(gè)IP信息包都必須包含有目的設(shè)備的IP地址妇多,信息包才可以正確地送到目的地伤哺。同一設(shè)備不可以擁有多個(gè)IP地址,所有使用IP的網(wǎng)絡(luò)設(shè)備至少有一個(gè)唯一的IP地址者祖。

1.1.2、IP路由
互聯(lián)網(wǎng)是由許多個(gè)網(wǎng)絡(luò)連接所形成的大型網(wǎng)絡(luò)绢彤。如果要在互聯(lián)網(wǎng)中傳送IP信息包七问,除了確保網(wǎng)絡(luò)上每個(gè)設(shè)備都有一個(gè)唯一的IP地址之外,網(wǎng)絡(luò)之間還必須有傳送的機(jī)制茫舶,才能將IP信息包通過(guò)一個(gè)個(gè)的網(wǎng)絡(luò)傳送到目的地械巡。此種傳送機(jī)制稱為IP路由。 [2]
各個(gè)網(wǎng)絡(luò)通過(guò)路由器相互連接饶氏。路由器的功能是為IP信息包選擇傳送的路徑讥耗。換言之,必須依靠沿途各路由器的通力合作疹启,才能將IP信息包送到目的地古程。在IP路由的過(guò)程中,由路由器負(fù)責(zé)選擇路徑喊崖,IP信息包則是被傳送的對(duì)象挣磨。

1.2、IP信息包的分割與重組
為了能把一個(gè)IP報(bào)文放在不同的物理幀中荤懂,最大IP報(bào)文的長(zhǎng)度就只能等于這條路徑上所有物理網(wǎng)絡(luò)的MTU的最小值茁裙。當(dāng)數(shù)據(jù)報(bào)通過(guò)一個(gè)可以傳輸長(zhǎng)度更大的幀的網(wǎng)絡(luò)時(shí),把數(shù)據(jù)報(bào)的大小限制在互聯(lián)網(wǎng)上最小的MTU之下不經(jīng)濟(jì)节仿;如果數(shù)據(jù)報(bào)的長(zhǎng)度超過(guò)互聯(lián)網(wǎng)中最小的MTU值的話晤锥,則當(dāng)該數(shù)據(jù)報(bào)在穿越該子網(wǎng)時(shí),就無(wú)法被封裝在一個(gè)幀中廊宪。

IP協(xié)議在發(fā)送IP報(bào)文時(shí)矾瘾,一般選擇一個(gè)合適的初始長(zhǎng)度女轿。如果這個(gè)報(bào)文要經(jīng)歷的中間物理網(wǎng)絡(luò)的MTU值比IP報(bào)文長(zhǎng)度要小,則IP協(xié)議把這個(gè)報(bào)文的數(shù)據(jù)部分分割成若干個(gè)較小的數(shù)據(jù)片霜威,組成較小的報(bào)文谈喳,然后放到物理幀中去發(fā)送。每個(gè)小的報(bào)文稱為一個(gè)分段戈泼。分段的動(dòng)作一般在路由器上進(jìn)行婿禽。如果路由器從某個(gè)網(wǎng)絡(luò)接口收到了一個(gè)IP報(bào)文,要向另外一個(gè)網(wǎng)絡(luò)轉(zhuǎn)發(fā)大猛,而該網(wǎng)絡(luò)的MTU比IP報(bào)文長(zhǎng)度要小扭倾,那么就要把該IP報(bào)文分成多個(gè)小IP分段后再分別發(fā)送。

重組是分段的逆過(guò)程挽绩,把若干個(gè)IP分段重新組合后還原為原來(lái)的IP報(bào)文膛壹。在目的端收到一個(gè)IP報(bào)文時(shí),可以根據(jù)其分段偏移和MF標(biāo)志位來(lái)判斷它是否是一個(gè)分段唉堪。如果MF位是0模聋,并且分段偏移為0,則表明這是一個(gè)完整的IP數(shù)據(jù)報(bào)唠亚。否則链方,如果分段偏移不為0,或者M(jìn)F標(biāo)志位為1灶搜,則表明它是一個(gè)分段祟蚀。這時(shí)目的地端需要實(shí)行分段重組。IP協(xié)議根據(jù)IP報(bào)文頭中的標(biāo)識(shí)符字段的值來(lái)確定哪些分段屬于同一個(gè)原始報(bào)文割卖,根據(jù)分段偏移來(lái)確定分段在原始報(bào)文中的位置前酿。如果一個(gè)IP數(shù)據(jù)報(bào)的所有分段都正確地到達(dá)目的地,則把它重新組織成一個(gè)完整的報(bào)文后交給上層協(xié)議去處理鹏溯。

1罢维、ARP及RARP協(xié)議
ARP 是根據(jù)IP地址獲取MAC地址的一種協(xié)議。

ARP(地址解析)協(xié)議是一種解析協(xié)議剿涮,本來(lái)主機(jī)是完全不知道這個(gè)IP對(duì)應(yīng)的是哪個(gè)主機(jī)的哪個(gè)接口言津,當(dāng)主機(jī)要發(fā)送一個(gè)IP包的時(shí)候,會(huì)首先查一下自己的ARP高速緩存(就是一個(gè)IP-MAC地址對(duì)應(yīng)表緩存)取试。

如果查詢的IP-MAC值對(duì)不存在悬槽,那么主機(jī)就向網(wǎng)絡(luò)發(fā)送一個(gè)ARP協(xié)議廣播包,這個(gè)廣播包里面就有待查詢的IP地址瞬浓,而直接收到這份廣播的包的所有主機(jī)都會(huì)查詢自己的IP地址初婆,如果收到廣播包的某一個(gè)主機(jī)發(fā)現(xiàn)自己符合條件,那么就準(zhǔn)備好一個(gè)包含自己的MAC地址的ARP包傳送給發(fā)送ARP廣播的主機(jī)。

而廣播主機(jī)拿到ARP包后會(huì)更新自己的ARP緩存(就是存放IP-MAC對(duì)應(yīng)表的地方)磅叛。發(fā)送廣播的主機(jī)就會(huì)用新的ARP緩存數(shù)據(jù)準(zhǔn)備好數(shù)據(jù)鏈路層的的數(shù)據(jù)包發(fā)送工作屑咳。
原文鏈接:https://blog.csdn.net/qq_24125575/article/details/105488168

Socket原理
1、什么是Socket
套接字(socket)是一個(gè)抽象層弊琴,應(yīng)用程序可以通過(guò)它發(fā)送或接收數(shù)據(jù)兆龙,可對(duì)其進(jìn)行像對(duì)文件一樣的打開(kāi)、讀寫和關(guān)閉等操作敲董。套接字允許應(yīng)用程序?qū)/O插入到網(wǎng)絡(luò)中紫皇,并與網(wǎng)絡(luò)中的其他應(yīng)用程序進(jìn)行通信。網(wǎng)絡(luò)套接字是IP地址與端口的組合腋寨。

傳輸層實(shí)現(xiàn)端到端的通信聪铺,因此,每一個(gè)傳輸層連接有兩個(gè)端點(diǎn)萄窜。那么铃剔,傳輸層連接的端點(diǎn)是什么呢?不是主機(jī)查刻,不是主機(jī)的IP地址键兜,不是應(yīng)用進(jìn)程,也不是傳輸層的協(xié)議端口穗泵。傳輸層連接的端點(diǎn)叫做套接字(socket)蝶押。根據(jù)RFC793的定義:端口號(hào)拼接到IP地址就構(gòu)成了套接字。所謂套接字火欧,實(shí)際上是一個(gè)通信端點(diǎn),每個(gè)套接字都有一個(gè)套接字序號(hào)茎截,包括主機(jī)的IP地址與一個(gè)16位的主機(jī)端口號(hào)苇侵,即形如(主機(jī)IP地址:端口號(hào))。例如企锌,如果IP地址是210.37.145.1榆浓,而端口號(hào)是23,那么得到套接字就是(210.37.145.1:23)撕攒。

那么套接字這個(gè)抽象層位于TCP/IP協(xié)議簇四層結(jié)構(gòu)中的哪個(gè)位置呢陡鹃?看下圖就一目了然了:


image.png

它位于應(yīng)用層與傳輸層之間,是一組封裝好的接口抖坪,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面萍鲸,對(duì)用戶來(lái)說(shuō),一組簡(jiǎn)單的接口就是全部擦俐,讓Socket去組織數(shù)據(jù)脊阴。


image.png

2、Java Socket實(shí)現(xiàn)
2.1、主要方法

Accept方法用于產(chǎn)生”阻塞”嘿期,直到接受到一個(gè)連接品擎,并且返回一個(gè)客戶端的Socket對(duì)象實(shí)例”感欤”阻塞”是一個(gè)術(shù)語(yǔ)萄传,它使程序運(yùn)行暫時(shí)”停留”在這個(gè)地方,直到一個(gè)會(huì)話產(chǎn)生蜜猾,然后程序繼續(xù)秀菱;通常”阻塞”是由循環(huán)產(chǎn)生的瓣铣。
getInputStream方法獲得網(wǎng)絡(luò)連接輸入答朋,同時(shí)返回一個(gè)InputStream對(duì)象實(shí)例。
getOutputStream方法連接的另一端將得到輸入棠笑,同時(shí)返回一個(gè)OutputStream對(duì)象實(shí)例梦碗。
2.2、服務(wù)器端

創(chuàng)建ServerSocket對(duì)象蓖救,綁定監(jiān)聽(tīng)端口洪规。
通過(guò)accept()方法監(jiān)聽(tīng)客戶端請(qǐng)求。
連接建立后循捺,通過(guò)輸入流讀取客戶端發(fā)送的請(qǐng)求信息斩例。
通過(guò)輸出流向客戶端發(fā)送響應(yīng)信息。
關(guān)閉響應(yīng)的資源从橘。
2.3念赶、客戶端

創(chuàng)建Socket對(duì)象,指明需要連接的服務(wù)器的地址和端口號(hào)恰力。
連接建立后叉谜,通過(guò)輸出流向服務(wù)器發(fā)送請(qǐng)求信息。
通過(guò)輸入流獲取服務(wù)器響應(yīng)的信息踩萎。
關(guān)閉相應(yīng)資源停局。
2.4、多線程實(shí)現(xiàn)服務(wù)器與多客戶端之間通信步驟

服務(wù)器端創(chuàng)建ServerSocket香府,循環(huán)調(diào)用accept()等待客戶端連接董栽。
客戶端創(chuàng)建一個(gè)socket并請(qǐng)求和服務(wù)器端連接。
服務(wù)器端接受客戶端請(qǐng)求企孩,創(chuàng)建socket與該客戶建立專線連接锭碳。
建立連接的兩個(gè)socket在一個(gè)單獨(dú)的線程上對(duì)話。
服務(wù)器端繼續(xù)等待新的連接柠硕。
2.5工禾、客戶端代碼

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class SocketClient {
public static void main(String args[]) throws Exception {
// 要連接的服務(wù)端IP地址和端口
String host = "127.0.0.1";
int port = 60000;
// 與服務(wù)端建立連接
Socket socket = new Socket(host, port);
// 建立連接后獲得輸出流
OutputStream outputStream = socket.getOutputStream();
String message = "hello server";
socket.getOutputStream().write(message.getBytes("UTF-8"));
//通過(guò)shutdownOutput告訴服務(wù)器已經(jīng)發(fā)送完數(shù)據(jù)运提,后續(xù)只能接受數(shù)據(jù)
socket.shutdownOutput();

InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
while ((len = inputStream.read(bytes)) != -1) {
  //注意指定編碼格式,發(fā)送方和接收方一定要統(tǒng)一闻葵,建議使用UTF-8
  sb.append(new String(bytes, 0, len,"UTF-8"));
}
System.out.println("get message from server: " + sb);

inputStream.close();
outputStream.close();
socket.close();
}
}

2.6民泵、服務(wù)器端代碼

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) throws Exception {
 // 監(jiān)聽(tīng)指定的端口
int port = 60000;
ServerSocket server = new ServerSocket(port);
// server將一直等待連接的到來(lái)
System.out.println("server將一直等待連接的到來(lái)");
Socket socket = server.accept();
// 建立好連接后,從socket中獲取輸入流槽畔,并建立緩沖區(qū)進(jìn)行讀取
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
//只有當(dāng)客戶端關(guān)閉它的輸出流的時(shí)候栈妆,服務(wù)端才能取得結(jié)尾的-1
while ((len = inputStream.read(bytes)) != -1) {
  // 注意指定編碼格式,發(fā)送方和接收方一定要統(tǒng)一厢钧,建議使用UTF-8
  sb.append(new String(bytes, 0, len, "UTF-8"));
}
System.out.println("get message from client: " + sb);

OutputStream outputStream = socket.getOutputStream();
outputStream.write("Hello Client,I get the message.".getBytes("UTF-8"));

inputStream.close();
outputStream.close();
socket.close();
server.close();
}
}

http協(xié)議
.http協(xié)議是hype text transfer protocol(超文本傳輸協(xié)議)的縮寫鳞尔,是一個(gè)基于請(qǐng)求與響應(yīng)模式的短連接,無(wú)狀態(tài)早直,應(yīng)用層的協(xié)議寥假,支持c/s模式,簡(jiǎn)單快速霞扬,靈活糕韧。,有四個(gè)版本喻圃,0.9萤彩,1.0亲桦,1.1裹驰,2.0.我們常用的是1.1版本。

0.9

0.9協(xié)議是適用于各種數(shù)據(jù)信息的簡(jiǎn)潔快速協(xié)議荒叶,但是遠(yuǎn)不能滿足日益發(fā)展的各種應(yīng)用的需要肆汹。0.9協(xié)議就是一個(gè)交換信息的無(wú)序協(xié)議愚墓,僅僅限于文字。由于無(wú)法進(jìn)行內(nèi)容的協(xié)商昂勉,在雙發(fā)的握手和協(xié)議中转绷,并有規(guī)定雙發(fā)的內(nèi)容是什么,也就是圖片是無(wú)法顯示和處理的硼啤。 [3]

1.0

到了1.0協(xié)議階段,也就是在1982年斧账,Tim Berners-Lee提出了HTTP/1.0谴返。在此后的不斷豐富和發(fā)展中,HTTP/1.0成為最重要的面向事務(wù)的應(yīng)用層協(xié)議咧织。該協(xié)議對(duì)每一次請(qǐng)求/響應(yīng)建立并拆除一次連接嗓袱。其特點(diǎn)是簡(jiǎn)單、易于管理习绢,所以它符合了大家的需要渠抹,得到了廣泛的應(yīng)用蝙昙。

1.1

在1.0協(xié)議中,雙方規(guī)定了連接方式和連接類型梧却,這已經(jīng)極大擴(kuò)展了HTTP的領(lǐng)域奇颠,但對(duì)于互聯(lián)網(wǎng)最重要的速度和效率,并沒(méi)有太多的考慮放航。畢竟烈拒,作為協(xié)議的制定者,當(dāng)時(shí)也沒(méi)有想到HTTP會(huì)有那么快的普及速度广鳍。 [3]

關(guān)于HTTP1.1協(xié)議的具體內(nèi)容可以參考RFC 2616荆几。 [4]

2.0

HTTP2.0的前身是HTTP1.0和HTTP1.1。雖然之前僅僅只有兩個(gè)版本赊时,但這兩個(gè)版本所包含的協(xié)議規(guī)范之龐大吨铸,足以讓任何一個(gè)有經(jīng)驗(yàn)的工程師為之頭疼。網(wǎng)絡(luò)協(xié)議新版本并不會(huì)馬上取代舊版本祖秒。實(shí)際上诞吱,1.0和1.1在之后很長(zhǎng)的一段時(shí)間內(nèi)一直并存,這是由于網(wǎng)絡(luò)基礎(chǔ)設(shè)施更新緩慢所決定的狈涮。 [5]

關(guān)于HTTP2.0協(xié)議的具體內(nèi)容可以參考RFC 7540狐胎。 [6]

C/S:支持C/S(客戶/服務(wù)器)模式
簡(jiǎn)單快速:客戶向服務(wù)器請(qǐng)求服務(wù)時(shí)歌馍,只需傳送請(qǐng)求方法和路徑握巢。

請(qǐng)求方法常用的有GET、HEAD松却、POST暴浦,每種方法規(guī)定了客戶與服務(wù)器聯(lián)系的類型不同。 由于HTTP協(xié)議簡(jiǎn)單晓锻,使得HTTP服務(wù)器的程序規(guī)模小歌焦,因而通信速度

靈活:允許傳輸任意類型的數(shù)據(jù)對(duì)象砚哆,由Content-Type標(biāo)記

短連接:每次處理一個(gè)請(qǐng)求独撇,處理完成后既斷開(kāi)(服務(wù)器處理完客戶的請(qǐng)求,并收到客戶的應(yīng)答后躁锁,即斷開(kāi)連接纷铣。采用這種方式可以節(jié)省傳輸時(shí)間。)

無(wú)狀態(tài):對(duì)事務(wù)處理沒(méi)有記憶能力战转,少狀態(tài)意味著果后續(xù)處理需要前面信息搜立,則它必須重傳,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大槐秧。
另一方面啄踊,在服務(wù)器不需要先前信息時(shí)它的應(yīng)答較快忧设。

HTTP是基于[客戶/服務(wù)器]模式,且面向連接的颠通。典型的HTTP[事務(wù)處理]有如下的過(guò)程:

(1)客戶與服務(wù)器建立連接址晕;

(2)客戶向服務(wù)器提出請(qǐng)求;

(3)服務(wù)器接受請(qǐng)求蒜哀,并根據(jù)請(qǐng)求返回相應(yīng)的文件作為應(yīng)答斩箫;

(4)客戶與服務(wù)器關(guān)閉連接。

客戶與服務(wù)器之間的HTTP連接是一種一次性連接撵儿,它限制每次連接只處理一個(gè)請(qǐng)求乘客,當(dāng)服務(wù)器返回本次請(qǐng)求的應(yīng)答后便立即關(guān)閉連接,下次請(qǐng)求再重新建立連接淀歇。

HTTP是一種[無(wú)狀態(tài)協(xié)議]即服務(wù)器不保留與客戶交易時(shí)的任何狀態(tài)易核。這就大大減輕了服務(wù)器記憶負(fù)擔(dān),從而保持較快的[響應(yīng)速度]
HTTP是一種面向?qū)ο蟮膮f(xié)議浪默。允許傳送任意類型的[數(shù)據(jù)對(duì)象]它通過(guò)[數(shù)據(jù)類型]和長(zhǎng)度來(lái)標(biāo)識(shí)所傳送的數(shù)據(jù)內(nèi)容和大小牡直,并允許對(duì)數(shù)據(jù)進(jìn)行壓縮傳送。

HTTP支持[持久連接](指不必為每個(gè)request object(例如很小的gif廣告圖像)的傳送建立一個(gè)新的TCP(socket)連接,減少TCP建立時(shí)間和相應(yīng)的系統(tǒng)損耗纳决。)碰逸,在HTTP / 0.9和1.0中,連接在單個(gè)請(qǐng)求/響應(yīng)對(duì)之后關(guān)閉阔加。在HTTP / 1.1中饵史,引入了保持活動(dòng)機(jī)制,其中連接可以重用于多個(gè)請(qǐng)求胜榔。這樣的[持久性]連接可以明顯減少請(qǐng)求延遲胳喷,因?yàn)樵诎l(fā)送第一個(gè)請(qǐng)求之后,客戶端不需要重新協(xié)商[TCP]3-Way-Handshake連接夭织。另一個(gè)積極的副作用是吭露,通常,由于TCP的緩慢啟動(dòng)機(jī)制尊惰,連接隨著時(shí)間的推移而變得更快讲竿。

該協(xié)議的1.1版還對(duì)HTTP / 1.0進(jìn)行了帶寬優(yōu)化改進(jìn)。例如弄屡,HTTP / 1.1引入了[分塊傳輸編碼]戴卜,以允許流傳輸而不是緩沖持久連接上的內(nèi)容。HTTP流水線進(jìn)一步減少了[延遲時(shí)間]琢岩,允許客戶端在等待每個(gè)響應(yīng)之前發(fā)送多個(gè)請(qǐng)求。協(xié)議的另一項(xiàng)[附加功能]是字節(jié)服務(wù)师脂,即服務(wù)器僅傳輸客戶端明確請(qǐng)求的資源部分担孔。

HTTP規(guī)范定義了9種請(qǐng)求方法江锨,每種請(qǐng)求方法規(guī)定了客戶和服務(wù)器之間不同的[信息交換]方式,常用的請(qǐng)求方法是GET和POST糕篇。服務(wù)器將根據(jù)客戶請(qǐng)求完成相應(yīng)操作啄育,并以應(yīng)答塊形式返回給客戶,最后關(guān)閉連接拌消。
HTTP報(bào)文由從[客戶機(jī)]到服務(wù)器的請(qǐng)求和從服務(wù)器到客戶機(jī)的響應(yīng)構(gòu)成挑豌。請(qǐng)求報(bào)文格式如下:

請(qǐng)求行 - 通用信息頭 - 請(qǐng)求頭 - 實(shí)體頭 - 報(bào)文主體

請(qǐng)求行以方法字段開(kāi)始,后面分別是URL字段和HTTP協(xié)議版本字段墩崩,并以CR[LF]結(jié)尾氓英。SP是[分隔符]。除了在最后的CRLF序列中CF和LF是必需的之外鹦筹,其他都可以不要铝阐。有關(guān)通用信息頭,請(qǐng)求頭和實(shí)體頭方面的具體內(nèi)容可以參照相關(guān)文件铐拐。

應(yīng)答報(bào)文格式如下:

狀態(tài)行 - 通用信息頭 - 響應(yīng)頭 - 實(shí)體頭 - 報(bào)文主體

狀態(tài)[碼元]由3位數(shù)字組成徘键,表示請(qǐng)求是否被理解或被滿足。[原因分析]是對(duì)原文的狀態(tài)碼作簡(jiǎn)短的描述遍蟋,狀態(tài)碼用來(lái)支持[自動(dòng)操作]吹害,而原因分析用來(lái)供用戶使用⌒榍啵客戶機(jī)無(wú)需用來(lái)檢查或顯示語(yǔ)法它呀。有關(guān)通用信息頭,響應(yīng)頭和實(shí)體頭方面的具體內(nèi)容可以參照相關(guān)文件挟憔。

http有兩種報(bào)文:請(qǐng)求報(bào)文和響應(yīng)報(bào)文

請(qǐng)求報(bào)文由請(qǐng)求行钟些,請(qǐng)求報(bào)頭,和請(qǐng)求數(shù)據(jù)組成

請(qǐng)求行:抓包第一行绊谭,包括請(qǐng)求方法政恍,url和http版本

請(qǐng)求報(bào)頭:指的就是題目中“里面的協(xié)議頭部”

請(qǐng)求數(shù)據(jù):指post方式提交的表單數(shù)據(jù)

響應(yīng)報(bào)文由狀態(tài)行,響應(yīng)報(bào)頭达传,響應(yīng)正文組成

狀態(tài)行:狀態(tài)碼

響應(yīng)報(bào)頭:同請(qǐng)求報(bào)頭

響應(yīng)正文:服務(wù)器返回的資源數(shù)據(jù)

接下來(lái)是http頭部篙耗,既請(qǐng)求報(bào)頭和響應(yīng)報(bào)頭,統(tǒng)稱消息報(bào)頭宪赶,消息報(bào)頭可以分為通用報(bào)頭宗弯,請(qǐng)求報(bào)頭,響應(yīng)報(bào)頭搂妻,實(shí)體報(bào)頭等

通用報(bào)頭和實(shí)體報(bào)頭既可以出現(xiàn)在請(qǐng)求報(bào)頭中蒙保,也可以出現(xiàn)在響應(yīng)報(bào)頭中,通用報(bào)頭包含的字段如:Date Connection Cache-Control,實(shí)體報(bào)頭中有Content-Type Content-Length Content-Language Content-Encoding.

請(qǐng)求報(bào)頭中包含的字段有:

Host,User-Agent,Accept-Encoding,Accept-Language,Connection

響應(yīng)報(bào)頭包含的字段:

Location欲主,Server

HTTP請(qǐng)求方法

HTTP請(qǐng)求方法有8種邓厕,分別是GET逝嚎、POST、DELETE详恼、PUT补君、HEAD、TRACE(trace)昧互、CONNECT(connect) 挽铁、OPTIONS(options)。

其中PUT敞掘、DELETE叽掘、POSTGET分別對(duì)應(yīng)著增刪改查渐逃,對(duì)于移動(dòng)開(kāi)發(fā)最常用的就是POST和GET了够掠。

GET:請(qǐng)求獲取Request-URI所標(biāo)識(shí)的資源

POST:在Request-URI所標(biāo)識(shí)的資源后附加新的數(shù)據(jù)

HEAD:請(qǐng)求獲取由Request-URI所標(biāo)識(shí)的資源的響應(yīng)消息報(bào)頭

PUT: 請(qǐng)求服務(wù)器存儲(chǔ)一個(gè)資源,并用Request-URI作為其標(biāo)識(shí)

DELETE :請(qǐng)求服務(wù)器刪除Request-URI所標(biāo)識(shí)的資源

TRACE : 請(qǐng)求服務(wù)器回送收到的請(qǐng)求信息茄菊,主要用于測(cè)試或診斷

CONNECT: HTTP/1.1協(xié)議中預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器疯潭。

OPTIONS :請(qǐng)求查詢服務(wù)器的性能,或者查詢與資源相關(guān)的選項(xiàng)和需求

狀態(tài)代碼

狀態(tài)代碼有三位數(shù)字組成面殖,第一個(gè)數(shù)字定義了響應(yīng)的類別竖哩,且有五種可能取值:

100~199:指示信息,表示請(qǐng)求已接收脊僚,繼續(xù)處理

200~299:請(qǐng)求成功相叁,表示請(qǐng)求已被成功接收、理解辽幌、接受

300~399:重定向增淹,要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作

400~499:客戶端錯(cuò)誤,請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn)

500~599:服務(wù)器端錯(cuò)誤乌企,服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求

常見(jiàn)的狀態(tài)碼如下:

200 OK:客戶端請(qǐng)求成功

400 Bad Request:客戶端請(qǐng)求有語(yǔ)法錯(cuò)誤虑润,不能被服務(wù)器所理解

401 Unauthorized:請(qǐng)求未經(jīng)授權(quán),這個(gè)狀態(tài)代碼必須和WWW-Authenticate報(bào)頭域一起使用

403 Forbidden:服務(wù)器收到請(qǐng)求加酵,但是拒絕提供服務(wù)

500 Internal Server Error:服務(wù)器發(fā)生不可預(yù)期的錯(cuò)誤

503 Server Unavailable:服務(wù)器當(dāng)前不能處理客戶端的請(qǐng)求拳喻,一段時(shí)間后可能恢復(fù)正常

HTTP的消息報(bào)頭

消息報(bào)頭分為通用報(bào)頭請(qǐng)求報(bào)頭猪腕、響應(yīng)報(bào)頭冗澈、實(shí)體報(bào)頭等。

消息頭由鍵值對(duì)組成陋葡,每行一對(duì)亚亲,關(guān)鍵字和值用英文冒號(hào)“:”分隔

通用報(bào)頭

既可以出現(xiàn)在請(qǐng)求報(bào)頭,也可以出現(xiàn)在響應(yīng)報(bào)頭中

Date:表示消息產(chǎn)生的日期和時(shí)間

Connection允許發(fā)送指定連接的選項(xiàng)

例如指定連接是連續(xù)的捌归,或者指定“close”選項(xiàng)颊亮,通知服務(wù)器,在響應(yīng)完成后陨溅,關(guān)閉連接

Cache-Control:用于指定緩存指令,緩存指令是單向的(響應(yīng)中出現(xiàn)的緩存指令在請(qǐng)求中未必會(huì)出現(xiàn))绍在,且是獨(dú)立的(一個(gè)消息的緩存指令不會(huì)影響另一個(gè)消息處理的緩存機(jī)制)

請(qǐng)求報(bào)頭

請(qǐng)求報(bào)頭通知服務(wù)器關(guān)于客戶端請(qǐng)求的信息门扇,典型的請(qǐng)求頭有:

Host請(qǐng)求的主機(jī)名,允許多個(gè)域名同處一個(gè)IP地址偿渡,即虛擬主機(jī)

User-Agent:發(fā)送請(qǐng)求的瀏覽器類型臼寄、操作系統(tǒng)等信息

Accept:客戶端可識(shí)別的內(nèi)容類型列表,用于指定客戶端接收那些類型的信息

Accept-Encoding:客戶端可識(shí)別的數(shù)據(jù)編碼

Accept-Language:表示瀏覽器所支持的語(yǔ)言類型

Connection:允許客戶端和服務(wù)器指定與請(qǐng)求/響應(yīng)連接有關(guān)的選項(xiàng)溜宽,例如這是為Keep-Alive則表示保持連接吉拳。

Transfer-Encoding:告知接收端為了保證報(bào)文的可靠傳輸,對(duì)報(bào)文采用了什么編碼方式适揉。

響應(yīng)報(bào)頭

用于服務(wù)器傳遞自身信息的響應(yīng)留攒,常見(jiàn)的響應(yīng)報(bào)頭:

Location:用于重定向接受者到一個(gè)新的位置,常用在更換域名的時(shí)候

Server:包含可服務(wù)器用來(lái)處理請(qǐng)求的系統(tǒng)信息嫉嘀,與User-Agent請(qǐng)求報(bào)頭是相對(duì)應(yīng)的

實(shí)體報(bào)頭

實(shí)體報(bào)頭用來(lái)定義被傳送資源的信息炼邀,既可以用于請(qǐng)求也可用于響應(yīng)

請(qǐng)求和響應(yīng)消息都可以傳送一個(gè)實(shí)體剪侮,常見(jiàn)的實(shí)體報(bào)頭為:

Content-Type:發(fā)送給接收者的實(shí)體正文的媒體類型

Content-Lenght:實(shí)體正文的長(zhǎng)度

Content-Language:描述資源所用的自然語(yǔ)言拭宁,沒(méi)有設(shè)置則該選項(xiàng)則認(rèn)為實(shí)體內(nèi)容將提供給所有的語(yǔ)言閱讀

Content-Encoding:實(shí)體報(bào)頭被用作媒體類型的修飾符,它的值指示了已經(jīng)被應(yīng)用到實(shí)體正文的附加內(nèi)容的編碼瓣俯,因而要獲得Content-Type報(bào)頭域中所引用的媒體類型杰标,必須采用相應(yīng)的解碼機(jī)制。

Last-Modified:實(shí)體報(bào)頭用于指示資源的最后修改日期和時(shí)間

Expires:實(shí)體報(bào)頭給出響應(yīng)過(guò)期的日期和時(shí)間

  1. http的get和post的區(qū)別

http是應(yīng)用層的協(xié)議彩匕,底層基于TCP/IP協(xié)議腔剂,所以本質(zhì)上,get和post請(qǐng)求都是TCP請(qǐng)求推掸。所以二者的區(qū)別都是體現(xiàn)在應(yīng)用層上(HTTP的規(guī)定和瀏覽器/服務(wù)器的限制)

1.參數(shù)的傳輸方式:GET參數(shù)通過(guò)URL傳遞桶蝎,POST放在Request body中,當(dāng)然由于GET/POST都是TCP鏈接谅畅。GET和POST能做的事情是一樣一樣的登渣。你要給GET加上request body,給POST帶上url參數(shù)毡泻,技術(shù)上是完全行的通的胜茧。但是HTTP規(guī)定,當(dāng)執(zhí)行GET請(qǐng)求的時(shí)候,要貼上GET的標(biāo)簽(設(shè)置method為GET)呻顽,而且要求把傳送的數(shù)據(jù)放在url中以方便記錄雹顺。如果是POST請(qǐng)求,就要貼上POST的標(biāo)簽廊遍,并把數(shù)據(jù)放在request body里嬉愧。當(dāng)然,你也可以在GET的時(shí)候往request body內(nèi)偷偷藏點(diǎn)數(shù)據(jù)喉前,但不同服務(wù)器的處理方式也是不同的没酣,有些服務(wù)器會(huì)讀出數(shù)據(jù),有些服務(wù)器直接忽略卵迂,所以裕便,雖然GET可以帶request body,也不能保證一定能被接收處理;也可以在POST的時(shí)候在url上也放一些數(shù)據(jù)见咒,讓人覺(jué)得傻乎乎的偿衰,畢竟不安全。HTTP只是個(gè)行為準(zhǔn)則改览,而TCP才是GET和POST怎么實(shí)現(xiàn)的基本

2.GET請(qǐng)求在URL中傳送的參數(shù)是有長(zhǎng)度限制的下翎,2k,而POST沒(méi)有恃疯,也有說(shuō)是2g的漏设。GET請(qǐng)求之所以限制2k,是因?yàn)閿?shù)據(jù)量太大對(duì)瀏覽器和服務(wù)器都是很大負(fù)擔(dān)今妄。業(yè)界不成文的規(guī)定是郑口,(大多數(shù))瀏覽器通常都會(huì)限制url長(zhǎng)度在2K個(gè)字節(jié),而(大多數(shù))服務(wù)器最多處理64K大小的url盾鳞。超過(guò)的部分犬性,恕不處理。

3.GET產(chǎn)生一個(gè)TCP數(shù)據(jù)包;POST產(chǎn)生兩個(gè)TCP數(shù)據(jù)包腾仅,.對(duì)于GET方式的請(qǐng)求乒裆,瀏覽器會(huì)把http header和data一并發(fā)送出去,服務(wù)器響應(yīng)200(返回?cái)?shù)據(jù))推励;而對(duì)于POST鹤耍,瀏覽器先發(fā)送header,服務(wù)器響應(yīng)100 continue验辞,瀏覽器再發(fā)送data稿黄,服務(wù)器響應(yīng)200 ok(返回?cái)?shù)據(jù))。不過(guò)要注意跌造,并不是所有瀏覽器都會(huì)在POST中發(fā)送兩次包杆怕,比如火狐

4.對(duì)參數(shù)的數(shù)據(jù)類型族购,GET只接受ASCII字符,而POST沒(méi)有限制陵珍。

5.GET比POST更不安全寝杖,因?yàn)閰?shù)直接暴露在URL上,所以不能用來(lái)傳遞敏感信息互纯。

6.GET請(qǐng)求只能進(jìn)行url編碼瑟幕,而POST支持多種編碼方式。

7.GET在瀏覽器回退時(shí)是無(wú)害的留潦,而POST會(huì)再次提交請(qǐng)求收苏。

8.GET產(chǎn)生的URL地址可以被Bookmark(書簽),而POST不可以愤兵。

9.GET請(qǐng)求會(huì)被瀏覽器主動(dòng)cache(緩存),而POST不會(huì)排吴,除非手動(dòng)設(shè)置秆乳。

  1. GET請(qǐng)求參數(shù)會(huì)被完整保留在瀏覽器歷史記錄里,而POST中的參數(shù)不會(huì)被保留钻哩。

  2. socket和http的區(qū)別:

Http協(xié)議:簡(jiǎn)單的對(duì)象訪問(wèn)協(xié)議屹堰,對(duì)應(yīng)于應(yīng)用層。Http協(xié)議是基于TCP鏈接的街氢。

tcp協(xié)議:對(duì)應(yīng)于傳輸層

ip協(xié)議:對(duì)應(yīng)與網(wǎng)絡(luò)層

TCP/IP是傳輸層協(xié)議扯键,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸;而Http是應(yīng)用層協(xié)議珊肃,主要解決如何包裝數(shù)據(jù)荣刑。

Socket是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議伦乔,而是一個(gè)調(diào)用接口(API)厉亏,通過(guò)Socket,我們才能使用TCP/IP協(xié)議烈和。

Http連接:http連接就是所謂的短連接爱只,及客戶端向服務(wù)器發(fā)送一次請(qǐng)求,服務(wù)器端響應(yīng)后連接即會(huì)斷掉招刹。

socket連接:socket連接及時(shí)所謂的長(zhǎng)連接恬试,理論上客戶端和服務(wù)端一旦建立連接,則不會(huì)主動(dòng)斷掉疯暑;但是由于各種環(huán)境因素可能會(huì)是連接斷開(kāi)训柴,比如說(shuō):服務(wù)器端或客戶端主機(jī)down了,網(wǎng)絡(luò)故障缰儿,或者兩者之間長(zhǎng)時(shí)間沒(méi)有數(shù)據(jù)傳輸畦粮,網(wǎng)絡(luò)防火墻可能會(huì)斷開(kāi)該鏈接已釋放網(wǎng)絡(luò)資源。所以當(dāng)一個(gè)socket連接中沒(méi)有數(shù)據(jù)的傳輸,那么為了連續(xù)的連接需要發(fā)送心跳消息宣赔,具體心跳消息格式是開(kāi)發(fā)者自己定義的预麸。

10. https

HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標(biāo)的HTTP通道儒将,簡(jiǎn)單講是HTTP的安全版吏祸。HTTP是應(yīng)用層協(xié)議,位于HTTP協(xié)議之下是傳輸協(xié)議TCP钩蚊。TCP負(fù)責(zé)傳輸贡翘,HTTP則定義了數(shù)據(jù)如何進(jìn)行包裝,在HTTP跟TCP中間加多了一層加密層TLS/SSL砰逻,SSL是個(gè)加密套件鸣驱,負(fù)責(zé)對(duì)HTTP的數(shù)據(jù)進(jìn)行加密。TLS是SSL的升級(jí)版◎鹋兀現(xiàn)在提到HTTPS踊东,加密套件基本指的是TLS。

傳輸加密的流程:http是應(yīng)用層將數(shù)據(jù)直接給到TCP進(jìn)行傳輸刚操,https是應(yīng)用層將數(shù)據(jù)給到TLS/SSL闸翅,將數(shù)據(jù)加密后,再給到TCP進(jìn)行傳輸菊霜。

HTTPS是如何加密數(shù)據(jù)的:

一般來(lái)說(shuō)坚冀,加密分為對(duì)稱加密、非對(duì)稱加密

對(duì)稱加密:

對(duì)稱加密的意思就是鉴逞,加密數(shù)據(jù)用的密鑰记某,跟解密數(shù)據(jù)用的密鑰是一樣的。

對(duì)稱加密的優(yōu)點(diǎn)在于加密构捡、解密效率通常比較高辙纬。缺點(diǎn)在于袜茧,數(shù)據(jù)發(fā)送方涉瘾、數(shù)據(jù)接收方需要協(xié)商叠蝇、共享同一把密鑰黔酥,并確保密鑰不泄露給其他人爷光。傳輸過(guò)程中容易被截獲形葬。

網(wǎng)上一個(gè)很形象的例子:假如現(xiàn)在小客與小服要進(jìn)行一次私密的對(duì)話合蔽,他們不希望這次對(duì)話內(nèi)容被其他外人知道料皇∩侗妫可是涡匀,我們平時(shí)的數(shù)據(jù)傳輸過(guò)程中又是明文傳輸?shù)模f(wàn)一被某個(gè)黑客把他們的對(duì)話內(nèi)容給竊取了溉知,那就難受了陨瘩。為了解決這個(gè)問(wèn)題腕够,小服這家伙想到了一個(gè)方法來(lái)加密數(shù)據(jù),讓黑客看不到具體的內(nèi)容舌劳。該方法是這樣子的:在每次數(shù)據(jù)傳輸之前帚湘,小服會(huì)先傳輸小客一把密鑰,然后小服在之后給小客發(fā)消息的過(guò)程中甚淡,會(huì)用這把密鑰對(duì)這些消息進(jìn)行加密大诸。小客在收到這些消息后,會(huì)用之前小服給的那把密鑰對(duì)這些消息進(jìn)行解密贯卦,這樣资柔,小客就能得到密文里面真正的數(shù)據(jù)了。如果小客要給小服發(fā)消息撵割,也同樣用這把密鑰來(lái)對(duì)消息進(jìn)行加密贿堰,小服收到后也用這把密鑰進(jìn)行解密。 這樣啡彬,就保證了數(shù)據(jù)傳輸?shù)陌踩浴?/p>

非對(duì)稱加密

非對(duì)稱加密的意思就是官边,加密數(shù)據(jù)用的密鑰(公鑰),跟解密數(shù)據(jù)用的密鑰(私鑰)是不一樣的外遇。

網(wǎng)上一個(gè)很形象的例子:小服還是挺聰明的,得意了一會(huì)之后契吉,小服意識(shí)到了密鑰會(huì)被截取這個(gè)問(wèn)題跳仿。倔強(qiáng)的小服又想到了另外一種方法:用非對(duì)稱加密的方法來(lái)加密數(shù)據(jù)。該方法是這樣的:小服和小客都擁有兩把鑰匙捐晶,一把鑰匙的公開(kāi)的(全世界都知道也沒(méi)關(guān)系)菲语,稱之為公鑰;而另一把鑰匙是保密(也就是只有自己才知道)惑灵,稱之為私鑰山上。并且,用公鑰加密的數(shù)據(jù)英支,只有對(duì)應(yīng)的私鑰才能解密佩憾;用私鑰加密的數(shù)據(jù),只有對(duì)應(yīng)的公鑰才能解密干花。所以在傳輸數(shù)據(jù)的過(guò)程中妄帘,小服在給小客傳輸數(shù)據(jù)的過(guò)程中,會(huì)用小客給他的公鑰進(jìn)行加密池凄,然后小客收到后抡驼,再用自己的私鑰進(jìn)行解密。小客給小服發(fā)消息的時(shí)候肿仑,也一樣會(huì)用小服給他的公鑰進(jìn)行加密致盟,然后小服再用自己的私鑰進(jìn)行解密碎税。 這樣,數(shù)據(jù)就能安全著到達(dá)雙方馏锡。是什么原因?qū)е路菍?duì)稱加密這種方法的不安全性呢雷蹂?它和對(duì)稱加密方法的不安全性不同。非對(duì)稱加密之所以不安全眷篇,是因?yàn)樾】褪盏搅斯€之后萎河,無(wú)法確定這把公鑰是否真的是小服。

解決的辦法就是數(shù)字證書:小服再給小客發(fā)公鑰的過(guò)程中蕉饼,會(huì)把公鑰以及小服的個(gè)人信息通過(guò)Hash算法生成消息摘要虐杯,為了防止摘要被人調(diào)換,小服還會(huì)用CA提供的私鑰對(duì)消息摘要進(jìn)行加密來(lái)形成數(shù)字簽名昧港,當(dāng)小客拿到這份數(shù)字證書之后擎椰,就會(huì)用CA提供的公鑰來(lái)對(duì)數(shù)字證書里面的數(shù)字簽名進(jìn)行解密得到消息摘要,然后對(duì)數(shù)字證書里面小服的公鑰和個(gè)人信息進(jìn)行Hash得到另一份消息摘要创肥,然后把兩份消息摘要進(jìn)行對(duì)比达舒,如果一樣,則證明這些東西確實(shí)是小服的叹侄,否則就不是巩搏。

11. 加密算法

對(duì)稱加密算法

Data Encryption Standard(DES)

DES 是一種典型的塊加密方法:將固定長(zhǎng)度的明文通過(guò)一系列復(fù)雜的操作變成同樣長(zhǎng)度的密文,塊的長(zhǎng)度為64位趾代。同時(shí)贯底,DES 使用的密鑰來(lái)自定義變換過(guò)程,因此算法認(rèn)為只有持有加密所用的密鑰的用戶才能解密密文撒强。 DES 的密鑰表面上是64位的禽捆,實(shí)際有效密鑰長(zhǎng)度為56位,其余8位可以用于奇偶校驗(yàn)飘哨。

DES 現(xiàn)在已經(jīng)不被視為一種安全的加密算法胚想,主要原因是它使用的56位密鑰過(guò)短。

為了提供實(shí)用所需的安全性芽隆,可以使用 DES 的派生算法 3DES 來(lái)進(jìn)行加密 (雖然3DES 也存在理論上的攻擊方法)浊服。

Advanced Encryption Standard(AES)

AES 在密碼學(xué)中又稱 Rijndael 加密法,用來(lái)替代原先的 DES胚吁,已經(jīng)被多方分析且廣泛使用臼闻。

DES與AES的比較

自DES 算法公諸于世以來(lái),學(xué)術(shù)界圍繞它的安全性等方面進(jìn)行了研究并展開(kāi)了激烈的爭(zhēng)論囤采。在技術(shù)上述呐,對(duì)DES的批評(píng)主要集中在以下幾個(gè)方面:

1、作為分組密碼蕉毯,DES 的加密單位僅有64 位二進(jìn)制乓搬,這對(duì)于數(shù)據(jù)傳輸來(lái)說(shuō)太小思犁,因?yàn)槊總€(gè)分組僅含8 個(gè)字符,而且其中某些位還要用于奇偶校驗(yàn)或其他通訊開(kāi)銷进肯。

2激蹲、DES 的密鑰的位數(shù)太短,只有56 比特江掩,而且各次迭代中使用的密鑰是遞推產(chǎn)生的学辱,這種相關(guān)必然降低密碼體制的安全性,在現(xiàn)有技術(shù)下用窮舉法尋找密鑰已趨于可行环形。

3策泣、DES 不能對(duì)抗差分和線性密碼分析。

4抬吟、DES 用戶實(shí)際使用的密鑰長(zhǎng)度為56bit萨咕,理論上最大加密強(qiáng)度為256。DES 算法要提高加密強(qiáng)度(例如增加密鑰長(zhǎng)度)火本,則系統(tǒng)開(kāi)銷呈指數(shù)增長(zhǎng)危队。除采用提高硬件功能和增加并行處理功能外,從算法本身和軟件技術(shù)方面都無(wú)法提高DES 算法的加密強(qiáng)度钙畔。

非對(duì)稱加密算法

RSA

1977年由 MIT 的 Ron Rivest茫陆、Adi Shamir 和 Leonard Adleman 一起提出,以他們?nèi)诵帐祥_(kāi)頭字母命名擎析,是一種獲得廣泛使用的非對(duì)稱加密算法簿盅。

對(duì)極大整數(shù)做因數(shù)分解的難度 (The Factoring Problem) 決定了 RSA 算法的可靠性。換言之叔锐,對(duì)一個(gè)極大整數(shù)做因數(shù)分解愈困難,RSA 算法就愈可靠见秽。假如有人找到一種快速因數(shù)分解的算法的話愉烙,那么用 RSA 加密的信息的可靠性就肯定會(huì)極度下降。目前看來(lái)找到這樣的算法的可能性非常小解取。

DES與RSA的比較

RSA算法的密鑰很長(zhǎng)步责,具有較好的安全性,但加密的計(jì)算量很大禀苦,加密速度較慢限制了其應(yīng)用范圍蔓肯。為減少計(jì)算量,在傳送信息時(shí)振乏,常采用傳統(tǒng)加密方法與公開(kāi)密鑰加密方法相結(jié)合的方式蔗包,即信息采用改進(jìn)的DES對(duì)話密鑰加密,然后使用RSA密鑰加密對(duì)話密鑰和信息摘要慧邮。對(duì)方收到信息后调限,用不同的密鑰解密并可核對(duì)信息摘要舟陆。

采用DES與RSA相結(jié)合的應(yīng)用,使它們的優(yōu)缺點(diǎn)正好互補(bǔ)耻矮,即DES加密速度快秦躯,適合加密較長(zhǎng)的報(bào)文,可用其加密明文裆装;RSA加密速度慢踱承,安全性好,應(yīng)用于DES 密鑰的加密哨免,可解決DES 密鑰分配的問(wèn)題茎活。

目前這種RSA和DES結(jié)合的方法已成為EMAIL保密通信標(biāo)準(zhǔn)。

12. Volley

1铁瞒、 Volley的特點(diǎn)

Volley是谷歌大會(huì)上推出的網(wǎng)絡(luò)通信框架(2.3之前使用HttpClient妙色,之后使用HttpUrlConnection),它既可以訪問(wèn)網(wǎng)絡(luò)獲取數(shù)據(jù)慧耍,也可以加載圖片身辨,并且在性能方面進(jìn)行了大幅度的調(diào)整,它的設(shè)計(jì)目的就是適合進(jìn)行數(shù)據(jù)量不大但通信頻繁的網(wǎng)絡(luò)操作芍碧,而對(duì)于大數(shù)據(jù)量的操作煌珊,比如文件下載,表現(xiàn)很糟糕泌豆,因?yàn)関olley處理http返回的默認(rèn)實(shí)現(xiàn)是BasicNetwork定庵,它會(huì)把返回的流全部導(dǎo)入內(nèi)存中,下載大文件會(huì)發(fā)生內(nèi)存溢出

2踪危、 Volley執(zhí)行的過(guò)程:

默認(rèn)情況下蔬浙,Volley中開(kāi)啟四個(gè)網(wǎng)絡(luò)調(diào)度線程和一個(gè)緩存調(diào)度線程,首先請(qǐng)求會(huì)加入緩存隊(duì)列贞远,畴博,緩存調(diào)度線程從緩存隊(duì)列中取出線程,如果找到該請(qǐng)求的緩存就直接讀取該緩存并解析蓝仲,然后回調(diào)給主線程俱病,如果沒(méi)有找到緩存的響應(yīng),則將這個(gè)請(qǐng)求加入網(wǎng)絡(luò)隊(duì)列袱结,然后網(wǎng)絡(luò)調(diào)度線程會(huì)輪詢?nèi)〕鼍W(wǎng)絡(luò)隊(duì)列中的請(qǐng)求亮隙,發(fā)起http請(qǐng)求,解析響應(yīng)并將響應(yīng)存入緩存垢夹,回調(diào)給主線程

3溢吻、 Volley為什么不適合下載上傳大文件?為什么適合數(shù)據(jù)量小的頻率高的請(qǐng)求果元?

1.volley基于請(qǐng)求隊(duì)列煤裙,Volley的網(wǎng)絡(luò)請(qǐng)求線程池默認(rèn)大小為4掩完。意味著可以并發(fā)進(jìn)行4個(gè)請(qǐng)求,大于4個(gè)硼砰,會(huì)排在隊(duì)列中且蓬。并發(fā)量小所以適合數(shù)據(jù)量下頻率高的請(qǐng)求

2.因?yàn)閂olley下載文件會(huì)將流存入內(nèi)存中(是一個(gè)小于4k的緩存池),大文件會(huì)導(dǎo)致內(nèi)存溢出题翰,所以不能下載大文件恶阴,不能上傳大文件的原因和1中差不多,設(shè)想你上傳了四個(gè)大文件豹障,同時(shí)占用了volley的四個(gè)線程冯事,導(dǎo)致其他網(wǎng)絡(luò)請(qǐng)求都阻塞在隊(duì)列中,造成反應(yīng)慢的現(xiàn)象

13. OKHttp
OkHttp是安卓上常用的網(wǎng)絡(luò)請(qǐng)求框架血公,不止可以發(fā)送http請(qǐng)求昵仅,還可以發(fā)送socket請(qǐng)求等。

內(nèi)置了連接池累魔,減少了請(qǐng)求延遲
支持緩存摔笤,減少重復(fù)的網(wǎng)絡(luò)請(qǐng)求
支持Cookie存儲(chǔ)
支持?jǐn)r截器,可以對(duì)不同的請(qǐng)求做攔截處理
支持get垦写、post等請(qǐng)求
支持文件上傳下載
支持json請(qǐng)求
支持同步吕世、異步處理

1.相較于Volley,它的最大并發(fā)量為64

2.使用連接池技術(shù)梯投,支持5個(gè)并發(fā)的socket連接命辖,默認(rèn)keepAlive時(shí)間為5分鐘,解決TCP握手和揮手的效率問(wèn)題分蓖,減少握手次數(shù)

3.支持Gzip壓縮尔艇,且操作對(duì)用戶透明,可以通過(guò)header設(shè)置么鹤,在發(fā)起請(qǐng)求的時(shí)候自動(dòng)加入header终娃,Accept-Encoding: gzip,而我們的服務(wù)器返回的時(shí)候header中有Content-Encoding: gzip

4.利用響應(yīng)緩存來(lái)避免重復(fù)的網(wǎng)絡(luò)請(qǐng)求

5.很方便的添加攔截器午磁,通常情況下尝抖,攔截器用來(lái)添加毡们,移除迅皇,轉(zhuǎn)換請(qǐng)求和響應(yīng)的頭部信息,比如添加公參等

6.請(qǐng)求失敗衙熔,自動(dòng)重連登颓,發(fā)生異常時(shí)重連,看源碼調(diào)用recover方法重連了一次

7.支持SPDY協(xié)議(SPDY是Google開(kāi)發(fā)的基于TCP的應(yīng)用層協(xié)議红氯,用以最小化網(wǎng)絡(luò)延遲框咙,提升網(wǎng)絡(luò)速度咕痛,優(yōu)化用戶的網(wǎng)絡(luò)使用體驗(yàn)。SPDY并不是一種用于替代HTTP的協(xié)議喇嘱,而是對(duì)HTTP協(xié)議的增強(qiáng)茉贡。新協(xié)議的功能包括數(shù)據(jù)流的多路復(fù)用、請(qǐng)求優(yōu)先級(jí)以及HTTP報(bào)頭壓縮者铜。谷歌表示腔丧,引入SPDY協(xié)議后,在實(shí)驗(yàn)室測(cè)試中頁(yè)面加載速度比原先快64%)

8.使用Okio來(lái)簡(jiǎn)化數(shù)據(jù)的訪問(wèn)與存儲(chǔ)作烟,提高性能

2愉粤、 OkHttp的缺點(diǎn)

1.消息回來(lái)需要切到主線程,主線程要自己去寫拿撩。

2.調(diào)用比較復(fù)雜衣厘,需要自己進(jìn)行封裝。

3.緩存失效:網(wǎng)絡(luò)請(qǐng)求時(shí)一般都會(huì)獲取手機(jī)的一些硬件或網(wǎng)絡(luò)信息压恒,比如使用的網(wǎng)絡(luò)環(huán)境影暴。同時(shí)為了信息傳輸?shù)陌踩裕赡苓€會(huì)對(duì)請(qǐng)求進(jìn)行加密涎显。在這些情況下OkHttp的緩存系統(tǒng)就會(huì)失效了坤检,導(dǎo)致用戶在無(wú)網(wǎng)絡(luò)情況下不能訪問(wèn)緩存。

3期吓、 OkHttp框架中都用到了哪些設(shè)計(jì)模式

1.最明顯的Builder設(shè)計(jì)模式早歇,如構(gòu)建對(duì)象OkHttpClient,還有單利模式

2.工廠方法模式讨勤,如源碼中的接口Call

3.觀察者模式如EventListener箭跳,監(jiān)聽(tīng)請(qǐng)求和響應(yīng)

4.策略模式

5.責(zé)任鏈模式,如攔截器

<meta charset="utf-8">

一:okhttp是什么

   大家都知道HTTP是現(xiàn)代應(yīng)用網(wǎng)絡(luò)請(qǐng)求的方式潭千,是一個(gè)簡(jiǎn)單的請(qǐng)求-響應(yīng)協(xié)議谱姓。在數(shù)據(jù)和媒體中進(jìn)行交換。有效地請(qǐng)求使您的東西加載更快刨晴,并節(jié)省帶寬屉来。OKHttp是安卓開(kāi)發(fā)中十分常用的網(wǎng)絡(luò)請(qǐng)求框架。

二:為什么使用

  1:緩存響應(yīng)數(shù)據(jù)來(lái)減少重復(fù)的網(wǎng)絡(luò)請(qǐng)求

   2:可以從很多常用的連接問(wèn)題中自動(dòng)恢復(fù)狈癞;(Okhttp處理了很多的網(wǎng)絡(luò)疑難雜癥:會(huì)從很多常用的連接問(wèn)題中自動(dòng)恢復(fù)茄靠。如果您的服        務(wù)器配置了多個(gè)IP地址,當(dāng)?shù)谝粋€(gè)IP連接失敗時(shí)蝶桶,OkHttp會(huì)嘗試連接下一個(gè)IP慨绳。)

   3:支持gzip壓縮響應(yīng)體

   4:使用簡(jiǎn)單,可擴(kuò)展性非常的強(qiáng);(責(zé)任鏈模式使得很容易添加一個(gè)自定義攔截器對(duì)請(qǐng)求和返回結(jié)果進(jìn)行處理)

三:用來(lái)干什么

  1:支持一般的get請(qǐng)求脐雪,post請(qǐng)求

   2:基于Http的文件上傳厌小,文件下載,上傳下載的進(jìn)度回調(diào)

   3:圖片加載

   4:支持請(qǐng)求回調(diào)战秋,對(duì)象返回

   5:   表單請(qǐng)求

四:請(qǐng)求流程

   1:生成一個(gè)OkHttpClient(用以總的控制)

   2:用各種鍵值對(duì)包裝我們的Request

   3:將請(qǐng)求加入隊(duì)列生成一個(gè)Call管理請(qǐng)求

   4:若是同步請(qǐng)求直接執(zhí)行excute等待處理返回Response璧亚,若為異步則實(shí)現(xiàn)Callback回調(diào),在onResponse里獲取Response參數(shù)
image

五:同步與異步的實(shí)現(xiàn)

在發(fā)起請(qǐng)求時(shí)脂信,整個(gè)框架主要通過(guò)Call來(lái)封裝每一次的請(qǐng)求涨岁。同時(shí)Call持有OkHttpClient和一份HttpEngine。而每一次的同步或者異步請(qǐng)求都會(huì)有Dispatcher的參與吉嚣。

Dispatcher

Dispatcher內(nèi)部實(shí)現(xiàn)了懶加載無(wú)邊界限制的線程池方式梢薪,同時(shí)該線程池采用了 SynchronousQueue這種阻塞隊(duì)列。SynchronousQueue每個(gè)插入操作必須等待另一個(gè)線程的移除操作尝哆,同樣任何一個(gè)移除操作都等待另一個(gè)線程的插入操作秉撇。因此此隊(duì)列內(nèi)部其實(shí)沒(méi)有任何一個(gè)元素,或者說(shuō)容量是0秋泄,嚴(yán)格說(shuō)并不是一種容器琐馆。由于隊(duì)列沒(méi)有容量,因此不能調(diào)用peek操作恒序,因?yàn)橹挥幸瞥貢r(shí)才有元素瘦麸。顯然這是一種快速傳遞元素的方式,也就是說(shuō)在這種情況下元素總是以最快的方式從插入者(生產(chǎn)者)傳遞給移除者(消費(fèi)者)歧胁,這在多任務(wù)隊(duì)列中是最快處理任務(wù)的方式滋饲。對(duì)于高頻繁請(qǐng)求的場(chǎng)景,無(wú)疑是最適合的喊巍。

同步

Dispatcher會(huì)在同步執(zhí)行任務(wù)隊(duì)列中記錄當(dāng)前被執(zhí)行過(guò)得任務(wù)Call屠缭,同時(shí)在當(dāng)前線程中去執(zhí)行Call的getResponseWithInterceptorChain()方法,直接獲取當(dāng)前的返回?cái)?shù)據(jù)Response崭参;

image

異步

異步執(zhí)行是通過(guò)Call.enqueue(Callback responseCallback)來(lái)執(zhí)行呵曹,在Dispatcher中添加一個(gè)封裝了Callback的Call的匿名內(nèi)部類Runnable來(lái)執(zhí)行當(dāng)前 的Call。這里一定要注意的地方這個(gè)AsyncCall是Call的匿名內(nèi)部類何暮。AsyncCall的execute方法仍然會(huì)回調(diào)到Call的 getResponseWithInterceptorChain方法來(lái)完成請(qǐng)求奄喂,同時(shí)將返回?cái)?shù)據(jù)或者狀態(tài)通過(guò)Callback來(lái)完成。

image

六:攔截器

image

攔截器可以注冊(cè)為應(yīng)用攔截器和網(wǎng)絡(luò)攔截器海洼。假如有一個(gè)壓縮攔截器和一個(gè)檢驗(yàn)和攔截器:你需要決定是先數(shù)據(jù)進(jìn)行壓縮然后檢驗(yàn)和跨新,還是先檢驗(yàn)和然后進(jìn)行壓縮。OkHttp使用列表來(lái)跟蹤攔截器贰军,并且攔截器按順序被調(diào)用玻蝌。

應(yīng)用攔截器

image

1:不需要關(guān)心像重定向和重試這樣的中間響應(yīng)。

2:總是調(diào)用一次词疼,即使HTTP響應(yīng)從緩存中獲取服務(wù)俯树。

3:監(jiān)視應(yīng)用原始意圖。不關(guān)心OkHttp注入的像If-None-Match頭贰盗。

4:允許短路并不調(diào)用Chain.proceed()许饿。

5:允許重試并執(zhí)行多個(gè)Chain.proceed()調(diào)用。

網(wǎng)絡(luò)攔截器

image

1:可以操作像重定向和重試這樣的中間響應(yīng)舵盈。

2:對(duì)于短路網(wǎng)絡(luò)的緩存響應(yīng)不會(huì)調(diào)用陋率。

3:監(jiān)視即將要通過(guò)網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)。

4:訪問(wèn)運(yùn)輸請(qǐng)求的Connection秽晚。

七:線程池技術(shù)

相比我們對(duì)于異步任務(wù)的需求應(yīng)該遇到了不少瓦糟,首先想到的便是Thread,handler等異步機(jī)制赴蝇,Java已經(jīng)做了很好的封裝菩浙,但是當(dāng)我們需要使用許多異步任務(wù),而這些任務(wù)只做了一點(diǎn)點(diǎn)事情就完成了它的使命句伶,當(dāng)我們不斷的創(chuàng)建劲蜻,銷毀線程的時(shí)候,對(duì)系統(tǒng)的開(kāi)銷是相當(dāng)大的考余,因?yàn)檫@些過(guò)程也是耗費(fèi)時(shí)間的先嬉,這個(gè)時(shí)候我們就需要用到線程池了,我們只要往池子里放任務(wù)楚堤,他就會(huì)自動(dòng)幫你管理線程的創(chuàng)建與銷毀疫蔓,利用緩存復(fù)用減少線程銷毀創(chuàng)建,優(yōu)化系統(tǒng)性能身冬。以下是線程池的優(yōu)點(diǎn):

1:通過(guò)對(duì)線程進(jìn)行緩存鳄袍,減少了創(chuàng)建銷毀的時(shí)間損失

2:通過(guò)控制線程數(shù)量閥值,減少了當(dāng)線程過(guò)少時(shí)帶來(lái)的CPU閑置(比如說(shuō)長(zhǎng)時(shí)間卡在I\O上了)與線程過(guò)多時(shí)對(duì)JVM的內(nèi)存與線程切換壓力而Disatcher內(nèi)部的核心即線程池

image

int corePoolSize: 最小并發(fā)線程數(shù)吏恭,這里并發(fā)同時(shí)包括空閑與活動(dòng)的線程拗小,如果是0的話,空閑一段時(shí)間后所有線程將全部被銷毀樱哼。

int maximumPoolSize: 最大線程數(shù)哀九,當(dāng)任務(wù)進(jìn)來(lái)時(shí)可以擴(kuò)充的線程最大值,當(dāng)大于了這個(gè)值就會(huì)根據(jù)丟棄處理機(jī)制來(lái)處理

long keepAliveTime: 當(dāng)線程數(shù)大于corePoolSize時(shí)搅幅,多余的空閑線程的最大存活時(shí)間阅束,類似于HTTP中的Keep-alive

TimeUnit unit: 時(shí)間單位,一般用秒

BlockingQueue workQueue: 工作隊(duì)列

ThreadFactory threadFactory: 單個(gè)線程的工廠茄唐,可以打Log息裸,設(shè)置Daemon(即當(dāng)JVM退出時(shí)蝇更,線程自動(dòng)結(jié)束)等

OkHttp內(nèi)Dispatcher原理其實(shí)當(dāng)我們調(diào)用client.newCall(request).enqueue(new callback(){...})的時(shí)候?qū)嵸|(zhì)是下圖

反向代理模式

為了解決單生產(chǎn)者多消費(fèi)者問(wèn)題,OkHttp采用了反向代理模式呼盆,來(lái)解決非阻塞年扩,高并發(fā)問(wèn)題

image

Dispatch模式

OkHttp內(nèi)Dispatcher原理其實(shí)當(dāng)我們調(diào)用client.newCall(request).enqueue(new callback(){...})的時(shí)候?qū)嵸|(zhì)是判斷線程池內(nèi)有無(wú)空閑,否則進(jìn)入等待隊(duì)列访圃,AsyncCall實(shí)質(zhì)是Runnable厨幻,當(dāng)任務(wù)執(zhí)行完畢后,總會(huì)調(diào)用finally{client.dispatcher().finished(this);}清除此任務(wù)腿时。我們回頭看看OkhttpClient初始化內(nèi)其它一些參數(shù)Expires况脆,Cache-Control,Last-Modified批糟,If-Modified-Since格了,ETag,If-None-Match...這些都牽扯到緩存問(wèn)題徽鼎。

Response response = getResponseWithInterceptorChain();

其實(shí)這個(gè)方法是返回我們的response對(duì)象笆搓。到這里整個(gè)流程已經(jīng)完畢。

使用OkHttpClient 的時(shí)候需要****注意****以下幾點(diǎn):

1:最好只使用一個(gè)共享的OkHttpClient 實(shí)例纬傲,將所有的網(wǎng)絡(luò)請(qǐng)求都通過(guò)這個(gè)實(shí)例處理满败。因?yàn)槊總€(gè)OkHttpClient 實(shí)例都有自己的連接池和線程池,重用這個(gè)實(shí)例能降低延時(shí)叹括,減少內(nèi)存消耗算墨,而重復(fù)創(chuàng)建新實(shí)例則會(huì)浪費(fèi)資源。

2:OkHttpClient的線程池和連接池在空閑的時(shí)候會(huì)自動(dòng)釋放汁雷,所以一般情況下不需要手動(dòng)關(guān)閉榨婆,但是如果出現(xiàn)極端內(nèi)存不足的情況仑鸥,可以使用以下代碼釋放內(nèi)存:

** client.dispatcher().executorService().shutdown(); //清除并關(guān)閉線程池**

** client.connectionPool().evictAll(); //清除并關(guān)閉連接池**

** client.cache().close(); **

3:如果對(duì)一些請(qǐng)求需要特殊定制凌彬,可以使用

OkHttpClient eagerClient = client.newBuilder()

** .readTimeout(500, TimeUnit.MILLISECONDS)**

** .build();**

這樣創(chuàng)建的實(shí)例與原實(shí)例共享線程池把介、連接池和其他設(shè)置項(xiàng),只需進(jìn)行少量配置就可以實(shí)現(xiàn)特殊需求厢漩。

Request

Request是網(wǎng)絡(luò)請(qǐng)求的對(duì)象膜眠,其本身的構(gòu)造函數(shù)是private的,只能通過(guò)Request.Builder來(lái)構(gòu)建溜嗜。下面代碼展示了常用的設(shè)置項(xiàng)宵膨。

Request request = new Request.Builder()

    .url("https://api.github.com/repos/square/okhttp/issues")                         //設(shè)置訪問(wèn)url

    .get()  //類似的有post、delete炸宵、patch辟躏、head、put等方法土全,對(duì)應(yīng)不同的網(wǎng)絡(luò)請(qǐng)求方法

    .header("User-Agent", "OkHttp Headers.java")                                       //設(shè)置header

    .addHeader("Accept", "application/json; q=0.5")                                     //添加header

    .removeHeader("User-Agent")                                                                //移除header

    .headers(new Headers.Builder().add("User-Agent", "OkHttp Headers.java").build())   

     //移除原有所有header捎琐,并設(shè)置新header

    .addHeader("Accept", "application/vnd.github.v3+json")

    .build();                                                                                                   //構(gòu)建request

RequestBody

在Request中使用post会涎、patch等方法時(shí),需要傳入一個(gè)RequestBody參數(shù)瑞凑,除了上一節(jié)講到的構(gòu)造方法外末秃,RequestBody還有兩個(gè)子類:FormBody和MultipartBody。

FromBody用于提交表單鍵值對(duì)拨黔,其作用類似于HTML中的<form>標(biāo)記。

RequestBody formBody = new FormBody.Builder() //提交表單鍵值對(duì)

    .add("platform", "android")                                                            //添加鍵值對(duì)

    .add("name", "XXX")

    .add("subject", "Hello")

    .addEncoded(URLEncoder.encode("詳細(xì)","GBK"), URLEncoder.encode("無(wú)","GBK"))

    //添加已編碼的鍵值對(duì)

    .add("描述","你好")          //其實(shí)會(huì)自動(dòng)編碼绰沥,但是無(wú)法控制編碼格式

    .build();

使用MultipartBody.Builder可以構(gòu)建與HTML文件上傳格式兼容的復(fù)雜請(qǐng)求體篱蝇。多塊請(qǐng)求體中每塊請(qǐng)求都是一個(gè)獨(dú)立的請(qǐng)求體,都可以定義自己的請(qǐng)求頭徽曲。這些請(qǐng)求頭應(yīng)該用于描述對(duì)應(yīng)的請(qǐng)求體零截,例如Content-Disposition,Content-Length秃臣,和Content-Type會(huì)自動(dòng)被添加到請(qǐng)求頭中涧衙。

Call

Call對(duì)象表示一個(gè)已經(jīng)準(zhǔn)備好可以執(zhí)行的請(qǐng)求,用這個(gè)對(duì)象可以查詢請(qǐng)求的執(zhí)行狀態(tài)奥此,或者取消當(dāng)前請(qǐng)求弧哎。它具有以下方法:

Call call=client.newCall(request); //獲取Call對(duì)象

Response response=call.execute(); //同步執(zhí)行網(wǎng)絡(luò)請(qǐng)求,不要在主線程執(zhí)行

call.enqueue(new Callback()); //異步執(zhí)行網(wǎng)絡(luò)請(qǐng)求

call.cancel(); //取消請(qǐng)求

call.isCanceled(); //查詢是否取消

call.isExecuted(); //查詢是否被執(zhí)行過(guò)

要注意的是稚虎,每個(gè)Call對(duì)象只能執(zhí)行一次請(qǐng)求撤嫩。如果想重復(fù)執(zhí)行相同的請(qǐng)求,可以:

Call reCall=client.newCall(call.request()); //獲取另一個(gè)相同配置的Call對(duì)象

Response

Response是網(wǎng)絡(luò)請(qǐng)求的結(jié)果下面是一些常用方法:

Response response=call.execute(); //獲取Response對(duì)象

response.code(); //請(qǐng)求的狀態(tài)碼

response.isSuccessful(); //如果狀態(tài)碼為[200..300)蠢终,則表明請(qǐng)求成功

Headers headers=response.headers(); //獲取響應(yīng)頭

List<String> names=response.headers("name"); //獲取響應(yīng)頭中的某個(gè)字段

ResponseBody body=response.body(); //獲取響應(yīng)體

其中ResponseBody代表響應(yīng)體序攘,用于操作網(wǎng)絡(luò)請(qǐng)求返回的內(nèi)容。常用方法如下:

body.contentLength(); //body的長(zhǎng)度

String content=body.string(); //以字符串形式解碼bodybyte[] byteContent=body.bytes(); //以字節(jié)數(shù)組形式解碼body

InputStreamReader reader=body.charStream(); //將body以字符流的形式解碼

InputStream inputStream=body.byteStream(); //將body以字節(jié)流的形式解碼

ResponseBody

1:ResponseBody必須關(guān)閉寻拂,不然可能造成資源泄漏程奠,你可以通過(guò)以下方法關(guān)閉ResponseBody,對(duì)同一個(gè)ResponseBody只要關(guān)閉一次就可以了。

Response.close();

Response.body().close();

Response.body().source().close();

Response.body().charStream().close();

Response.body().byteString().close();

Response.body().bytes();

Response.body().string();

2:ResponseBody只能被消費(fèi)一次祭钉,也就是string(),bytes(),byteStream()或 charStream()方法只能調(diào)用其中一個(gè)瞄沙。

3:如果ResponseBody中的數(shù)據(jù)很大,則不應(yīng)該使用bytes() 或 string()方法慌核,它們會(huì)將結(jié)果一次性讀入內(nèi)存帕识,而應(yīng)該使用byteStream()或 charStream(),以流的方式讀取數(shù)據(jù)遂铡。

八:OkHttp中的設(shè)計(jì)模式

1:責(zé)任鏈模式:攔截器鏈

2:?jiǎn)卫J剑壕€程池

3:觀察者模式:各種回調(diào)監(jiān)聽(tīng)

4:策略模式:緩存策略

5:Builder模式:OkHttpClient的構(gòu)建過(guò)程

作者:小阿飛的小蝴蝶
鏈接:http://www.reibang.com/p/c3cd14edc777
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有肮疗。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處扒接。

14. Retrofit

Retrofit底層是基于OkHttp實(shí)現(xiàn)的伪货,與其他網(wǎng)絡(luò)框架不同的是们衙,它更多使用運(yùn)行時(shí)注解的方式提供功能

1、 原理

通過(guò)java接口以及注解來(lái)描述網(wǎng)絡(luò)請(qǐng)求碱呼,并用動(dòng)態(tài)代理的方式生成網(wǎng)絡(luò)請(qǐng)求的request蒙挑,然后通過(guò)client調(diào)用相應(yīng)的網(wǎng)絡(luò)框架(默認(rèn)okhttp)去發(fā)起網(wǎng)絡(luò)請(qǐng)求,并將返回的response通過(guò)converterFactorty轉(zhuǎn)換成相應(yīng)的數(shù)據(jù)model愚臀,最后通過(guò)calladapter轉(zhuǎn)換成其他數(shù)據(jù)方式(如rxjava Observable)

2忆蚀、 Retrofit流程

(1)通過(guò)解析網(wǎng)絡(luò)請(qǐng)求接口的注解配置網(wǎng)絡(luò)請(qǐng)求參數(shù)

(2)通過(guò) 動(dòng)態(tài)代理 生成 網(wǎng)絡(luò)請(qǐng)求對(duì)象

(3)通過(guò) 網(wǎng)絡(luò)請(qǐng)求適配器將網(wǎng)絡(luò)請(qǐng)求對(duì)象 進(jìn)行平臺(tái)適配

(4)通過(guò) 網(wǎng)絡(luò)請(qǐng)求執(zhí)行器 發(fā)送網(wǎng)絡(luò)請(qǐng)求

(5)通過(guò) 數(shù)據(jù)轉(zhuǎn)換器 解析服務(wù)器返回的數(shù)據(jù)

(6)通過(guò) 回調(diào)執(zhí)行器 切換線程(子線程 ->>主線程)

(7)用戶在主線程處理返回結(jié)果

3、 Retrofit優(yōu)點(diǎn)

1.可以配置不同HTTP client來(lái)實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求姑裂,如okhttp馋袜、httpclient等;

2.請(qǐng)求的方法參數(shù)注解都可以定制舶斧;

3.支持同步欣鳖、異步和RxJava;

4.超級(jí)解耦茴厉;

5.可以配置不同的反序列化工具來(lái)解析數(shù)據(jù)泽台,如json、xml等

6.框架使用了很多設(shè)計(jì)模式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矾缓,一起剝皮案震驚了整個(gè)濱河市怀酷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嗜闻,老刑警劉巖胰坟,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異泞辐,居然都是意外死亡笔横,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門咐吼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吹缔,“玉大人,你說(shuō)我怎么就攤上這事锯茄∠崽粒” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵肌幽,是天一觀的道長(zhǎng)晚碾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)喂急,這世上最難降的妖魔是什么格嘁? 我笑而不...
    開(kāi)封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮廊移,結(jié)果婚禮上糕簿,老公的妹妹穿的比我還像新娘探入。我一直安慰自己,他們只是感情好懂诗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布蜂嗽。 她就那樣靜靜地躺著,像睡著了一般殃恒。 火紅的嫁衣襯著肌膚如雪植旧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天离唐,我揣著相機(jī)與錄音病附,去河邊找鬼。 笑死侯繁,一個(gè)胖子當(dāng)著我的面吹牛胖喳,可吹牛的內(nèi)容都是我干的泡躯。 我是一名探鬼主播贮竟,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼较剃!你這毒婦竟也來(lái)了咕别?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤写穴,失蹤者是張志新(化名)和其女友劉穎惰拱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體啊送,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偿短,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了馋没。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昔逗。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖篷朵,靈堂內(nèi)的尸體忽然破棺而出勾怒,到底是詐尸還是另有隱情,我是刑警寧澤声旺,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布笔链,位于F島的核電站,受9級(jí)特大地震影響腮猖,放射性物質(zhì)發(fā)生泄漏鉴扫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一澈缺、第九天 我趴在偏房一處隱蔽的房頂上張望幔妨。 院中可真熱鬧鹦赎,春花似錦、人聲如沸误堡。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锁施。三九已至陪踩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悉抵,已是汗流浹背肩狂。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姥饰,地道東北人傻谁。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像列粪,于是被迫代替她去往敵國(guó)和親审磁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容