TCP問題分析
網(wǎng)絡(luò)的五層協(xié)議
物理層
數(shù)據(jù)鏈路層
-
網(wǎng)絡(luò)層
渴杆,IP協(xié)議,ICMP協(xié)議(ping) -
傳輸層
盖奈,傳輸層有兩個協(xié)議混坞,面向連接的TCP和無連接的UDP,TCP是點(diǎn)對點(diǎn)的可靠連接钢坦,保證數(shù)據(jù)順序必達(dá)究孕,UDP是無連接的,不保證數(shù)據(jù)順序必達(dá)爹凹,UDP的傳輸效率要比TCP高厨诸,但是可能會丟包,而且一個UDP分段最多只能發(fā)送65535個字節(jié)逛万,TCP則是數(shù)據(jù)流的形式進(jìn)行數(shù)據(jù)傳輸?shù)挠锯瑢τ趹?yīng)用層來說,并沒有限制一次性可發(fā)送的數(shù)據(jù)宇植,只有在TCP協(xié)議這一層會對應(yīng)用層傳輸下來的數(shù)據(jù)做分段重組得封,這個跟SYN的MMS(Max segment size)有關(guān),表示TCP往另一端發(fā)送的最大塊數(shù)據(jù)的長度 -
應(yīng)用層
指郁,F(xiàn)TP忙上,HTTP,HTTPS闲坎,STMP等這些基于TCP協(xié)議實(shí)現(xiàn)的疫粥,而DNS,DHCP(動態(tài)主機(jī)配置協(xié)議腰懂,一種局域網(wǎng)協(xié)議)等是基于UDP協(xié)議實(shí)現(xiàn)的
TCP協(xié)議
-
TCP協(xié)議的Header組成梗逮,TCP協(xié)議首部,如果除去Options(選項(xiàng))的長度绣溜,有20個字節(jié)長度慷彤,IP協(xié)議首部也有20個字節(jié)的長度
TCP三次握手
[圖片上傳中...(tcp3.jpg-a081f-1513993970933-0)]
[圖片上傳中...(tcp4.jpg-9173c2-1513993970933-1)]
這邊有幾個比較重要的點(diǎn),主機(jī)A發(fā)起SYN,假設(shè)序號Seq為a底哗,發(fā)送成功后A進(jìn)入了SYN_SENT狀態(tài)岁诉,主機(jī)B收到A發(fā)的SYN后給一個SYN+ACK,發(fā)送成功后B進(jìn)入SYN_RCVD狀態(tài)跋选,假設(shè)序號Seq為b涕癣,那么確認(rèn)號Ack必須為a+1,以此來標(biāo)記確實(shí)收到了A發(fā)過來的SYN前标,同時也說明下一次A要是再發(fā)消息過來坠韩,那么序號Seq必須是a+1,主機(jī)A收到B發(fā)過來的SYN+ACK后炼列,進(jìn)入ESTABLISHED狀態(tài)同眯,表示A的TCP已經(jīng)可用,然后再回復(fù)一個ACK給B唯鸭,序號Seq為a+1,確認(rèn)號Ack為b+1硅确,B收到后狀態(tài)也變?yōu)镋STABLISHED狀態(tài),這時候TCP的三次握手就完成了
TCP四次揮手
和三次握手比較類似菱农,主機(jī)A主動發(fā)送FIN缭付,Seq為a,ack為x循未,然后A進(jìn)入FIN_WAIT1狀態(tài)陷猫,B進(jìn)入CLOSE_WAIT狀態(tài),主機(jī)B收到A發(fā)過來的FIN之后的妖,先回復(fù)一個FIN+ACK绣檬,Seq為b,ack為a+1嫂粟,然后B進(jìn)入LAST_ACK狀態(tài)娇未,主機(jī)A收到B發(fā)的FIN+ACK后,回復(fù)一個ACK星虹,Seq為a+1零抬,Ack為b+1,A進(jìn)入TIME_WAIT狀態(tài)宽涌,B收到A的ACK后平夜,進(jìn)入CLOSED,然后A會再等一小段時間(2MSL超時)后進(jìn)入CLOSED狀態(tài)卸亮,TCP4次揮手完成忽妒,其實(shí)從抓包來看,并沒有發(fā)生四次交互,因?yàn)锽的ACK和FIN合并在一起發(fā)出去了锰扶,這個也是TCP傳輸?shù)囊环N策略献酗,減少一次交互,增加了網(wǎng)絡(luò)的效率坷牛,4次揮手我認(rèn)為是邏輯上的4個步驟
以下內(nèi)容都特么是從書里抄的
- TIME_WAIT狀態(tài)也稱為2MSL等待狀態(tài)罕偎。每個具體TCP實(shí)現(xiàn)必須選擇一個報文段最大生
存時間MSLMaximum Segment Lifetime)。它是任何報文段被丟棄前在網(wǎng)絡(luò)內(nèi)的最長時間京闰。
我們知道這個時間是有限的颜及,因?yàn)門CP報文段以IP數(shù)據(jù)報在網(wǎng)絡(luò)內(nèi)傳輸,而IP數(shù)據(jù)報則有限制
其生存時間的TTL字段 - 當(dāng)TCP執(zhí)行一個主動關(guān)閉蹂楣,并發(fā)回最后一個ACK俏站,該連接必須在TIME_WAIT狀態(tài)停留的時間為2倍的MSL。這樣可讓TCP再次發(fā)送最后的ACK以防這個ACK丟失(另一端超時并重發(fā)最后的FIN)
- 在FIN_WAIT_2狀態(tài)我們已經(jīng)發(fā)出了FIN痊土,并且另一端也已對它進(jìn)行確認(rèn)肄扎。除非我們在實(shí)
行半關(guān)閉,否則將等待另一端的應(yīng)用層意識到它已收到一個文件結(jié)束符說明赁酝,并向我們發(fā)一
個FIN來關(guān)閉另一方向的連接犯祠。只有當(dāng)另一端的進(jìn)程完成這個關(guān)閉,我們這端才會從FIN_WAIT_2狀態(tài)進(jìn)入TIME_WAIT狀態(tài)酌呆,這意味著我們這端可能永遠(yuǎn)保持這個狀態(tài)衡载,另一端也將處于CLOSE_WAIT狀態(tài),并一直保持這個狀態(tài)直到應(yīng)用層決定進(jìn)行關(guān)閉
TCP選項(xiàng)
- MSS最大報文長度就是其中一個選項(xiàng)
- Timestamps時間戳(TCP Option - Timestamps: TSval 4294941817, TSecr 0)TSval為發(fā)起端發(fā)送這個消息包的本地時間隙袁,TSecr為發(fā)起端收到對方消息包的發(fā)送時間痰娱,即對方消息包中的TSval,由于這個是SYN包菩收,所以此時并沒有收到任何對方的消息梨睁,TSecr為0
- Window scale窗口擴(kuò)大因子,用來控制Window窗口的大小
擁塞控制
Nagle算法
- 該算法要求一個TCP連接上最多只能有一個未被確認(rèn)的未完成的小分組娜饵,在該分組的確認(rèn)到達(dá)之前不能發(fā)送其他的小分組而姐。相反,TCP收集這些少量的分組划咐,并在確認(rèn)到來時以一個分組的方式發(fā)出去拴念。該算法的優(yōu)越之處在于它是自適應(yīng)的:確認(rèn)到達(dá)得越快,數(shù)據(jù)也就發(fā)送得越快褐缠。而在希望減少微小分組數(shù)目的低速廣域網(wǎng)上政鼠,則會發(fā)送更少的分組
/**
* Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
*
* @param on <code>true</code> to enable TCP_NODELAY,
* <code>false</code> to disable.
*
* @exception SocketException if there is an error
* in the underlying protocol, such as a TCP error.
*
* @since JDK1.1
*
* @see #getTcpNoDelay()
*/
public void setTcpNoDelay(boolean on) throws SocketException {
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
}
以上是應(yīng)用層提供的是否開啟Nagle算法的接口,默認(rèn)為false队魏,即開啟Nagle算法
這個是未用Nagle算法的抓包信息
滑動窗口
對于發(fā)送方來說:
- Sent and Acknowledged:這些數(shù)據(jù)表示已經(jīng)發(fā)送成功并已經(jīng)被確認(rèn)的數(shù)據(jù)公般,這些數(shù)據(jù)其實(shí)的位置是在窗口之外了万搔,因?yàn)榇翱趦?nèi)順序最低的被確認(rèn)之后,要移除窗口官帘,實(shí)際上是窗口進(jìn)行合攏瞬雹,同時打開接收新的帶發(fā)送的數(shù)據(jù)
- Send But Not Yet Acknowledged:這部分?jǐn)?shù)據(jù)稱為發(fā)送但沒有被確認(rèn),數(shù)據(jù)被發(fā)送出去刽虹,沒有收到接收端的ACK酗捌,認(rèn)為并沒有完成發(fā)送,這個屬于窗口內(nèi)的數(shù)據(jù)
- Not Sent涌哲,Recipient Ready to Receive:這部分是盡快發(fā)送的數(shù)據(jù)胖缤,這部分?jǐn)?shù)據(jù)已經(jīng)被加載到緩存中,也就是窗口中了阀圾,等待發(fā)送哪廓,其實(shí)這個窗口是完全有接收方告知的,接收方告知還是能夠接受這些包初烘,所以發(fā)送方需要盡快的發(fā)送這些包
- Not Sent涡真,Recipient Not Ready to Receive: 這些數(shù)據(jù)屬于未發(fā)送,同時接收端也不允許發(fā)送的肾筐,因?yàn)檫@些數(shù)據(jù)已經(jīng)超出了發(fā)送端所接收的范圍
對于接收方來說:
- Received and ACK Not Send to Process:這部分?jǐn)?shù)據(jù)屬于接收了數(shù)據(jù)但是還沒有被上層的應(yīng)用程序接收综膀,也是被緩存在窗口內(nèi)
- Received Not ACK: 已經(jīng)接收,但是還沒有回復(fù)ACK局齿,這些包可能輸屬于Delay ACK的范疇了
- Not Received:有空位,還沒有被接收的數(shù)據(jù)
窗口的動態(tài)調(diào)整:
- 客戶端給服務(wù)器發(fā)送了50個字節(jié)橄登,然后服務(wù)器回了Ack抓歼,并且告知Win=0,客戶端收到服務(wù)器的Ack之后發(fā)現(xiàn)服務(wù)器這時候已經(jīng)不能夠接收數(shù)據(jù)了拢锹,客戶端就會把數(shù)據(jù)先緩存起來谣妻,并不在發(fā)送數(shù)據(jù),等收到服務(wù)器的窗口更新后Win=20卒稳,發(fā)現(xiàn)服務(wù)器重新能夠接收20個字節(jié)了蹋半,這時候客戶端才繼續(xù)發(fā)送數(shù)據(jù),這里其實(shí)也就是流量控制充坑,同時避免過多的數(shù)據(jù)寫入到網(wǎng)絡(luò)鏈路中减江,加入鏈路的帶寬很小,過多的數(shù)據(jù)寫入會造成擁塞
慢啟動
- 慢啟動為發(fā)送方的TCP增加了另一個窗口:擁塞窗口(congestion window)捻爷,記為cwnd辈灼;當(dāng)與另一個網(wǎng)絡(luò)的主機(jī)建立 TCP連接時,擁塞窗口被初始化為 1個報文段(即另一端通告的報文段大幸查)巡莹;每收到一個ACK,擁塞窗口就增加一個報段(cwnd以字節(jié)為單位,但是慢啟動以報文段大小為單位進(jìn)行增加)降宅;發(fā)送方取擁塞窗口與通告窗口中的最小值作為發(fā)送上限骂远;擁塞窗口是發(fā)送方使用的流量控制,而通告窗口則是接收方使用的流量控制
擁塞避免
- ssthresh腰根,這個是一個閥值激才,當(dāng)cwnd小于這個閥值的時候采用慢啟動,那么cwnd就會以指數(shù)增長唠雕,當(dāng)cwnd大于ssthresh的時候贸营,這時候就不用慢啟動算法,改用擁塞避免算法岩睁,擁塞避免算法是在每次收到消息的ack的時候cwnd增加1钞脂,這時候cwnd就變成線性增長
快速重傳
- 連續(xù)收到3次或者3次以上的重復(fù)Ack,就會觸發(fā)一次快速重傳
超時重傳
- RTT捕儒,消息包發(fā)送和收到Ack的往返時間冰啃,每一個消息包的RTT都可能不一樣,TCP會根據(jù)消息包的RTT去計算下一次重傳的時間間隔刘莹,RTT的計算公式是:R← R+ ( 1- )M阎毅,這里的 是一個推薦值為 0.9的平滑因子,每次進(jìn)行新測量的時候点弯,這個被平滑的RTT將得到更新扇调,每個新估計的90%來自前一個估計,而10%則取自新的測量
- RTO(Retransmission TimeOut)抢肛,這個是重傳超時時間狼钮,也就是下重傳消息需要等待Ack的時間,超過這個時間就再次發(fā)起下一次重傳
TCP抓包分析
- wireshark工具來查看tcpdump的抓包
- 對于有root過的android手機(jī)捡絮,如果手機(jī)系統(tǒng)中已經(jīng)內(nèi)置了tcpdump熬芜,可以直接使用tcpdump命令開啟抓包:tcpdump -i any -p -w /sdcard/netlog/dumpFileName,這個是我平時比較常用的抓包命令福稳,是全部都抓涎拉,無論是無線網(wǎng)卡還是數(shù)據(jù)網(wǎng)絡(luò),這種抓包命令在網(wǎng)絡(luò)切換的圆,網(wǎng)絡(luò)斷線重連的時候依然能保持抓包鼓拧,如果采用指定數(shù)據(jù)網(wǎng)絡(luò)的抓包,例如:tcpdump -i “aaa” -p -w /sdcard/netlog/dumpFileName越妈,其中“aaa”是數(shù)據(jù)網(wǎng)絡(luò)的一個名稱毁枯,那當(dāng)設(shè)備網(wǎng)絡(luò)從數(shù)據(jù)網(wǎng)絡(luò)切換到無限網(wǎng)絡(luò),這時候抓包就會斷了叮称,或者數(shù)據(jù)網(wǎng)絡(luò)斷線重連這時候抓包也會停止种玛,因此推薦采用any的抓包方式藐鹤,輸入命令后可以用ps | grep tcpdump命令看下抓包進(jìn)程是否運(yùn)行
- 如果手機(jī)系統(tǒng)中把tcpdump模塊給裁剪掉,那么需要去網(wǎng)上下載tcpdump赂韵,然后執(zhí)行如下步驟:
adb push tcpdump /sdcard/
adb Shell
su
cat /sdcard/tcpdump > /system/bin/tcpdump
上一條命令如果提示沒有權(quán)限娱节,接著執(zhí)行如下命令嘗試給 /system 目錄增加寫權(quán)限:
su
mount
在mount結(jié)果中找到包含/system的一行,類似如下:
/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0
去處/system前半行祭示,即/dev/block/platform/msm_sdcc.1/by-name/system肄满,執(zhí)行如下命令:
mount -o remount /dev/block/platform/msm_sdcc.1/by-name/system /system
這個時候/system就擁有寫權(quán)限了,繼續(xù)執(zhí)行:
cat /sdcard/tcpdump > /system/bin/tcpdump
chmod 777 /system/bin/tcpdump
到此為止质涛,tcpdump就成功安裝到了/system/bin/目錄下稠歉,接著用如下命令還是抓包
Java中的Socket異常分析
connection reset
- 在TCP消息協(xié)議包中,RST標(biāo)志代表連接終止汇陆,對于應(yīng)用層來說可能會報connection reset
- 當(dāng)A發(fā)送一個消息包給B怒炸,但是遲遲沒有收到B的Ack,這時候A開始重傳毡代,并且重傳一直不成功阅羹,知道最后一次重傳失敗之后,A會發(fā)起一個reset標(biāo)志
- 當(dāng)A關(guān)閉的TCP連接教寂,這時候還收到B發(fā)過來的數(shù)據(jù)捏鱼,A會立馬觸發(fā)一個reset
SocketException: Software caused connection abort
- 這個異常對于Android來說,是設(shè)備斷網(wǎng)了酪耕,同時會有一個網(wǎng)絡(luò)切換廣播
socket closed
- 當(dāng)java中的socket被close掉之后导梆,如果繼續(xù)往socket中寫數(shù)據(jù),就會報socket closed異常
SocketTimeoutException:connect timeout/ConnectException: Connection timed out
-
從字面意義上來理解就是連接超時迂烁,從抓包層面來看就是A對B發(fā)起一個TCP連接看尼,那么A就會發(fā)起一個SYN,但是遲遲沒有收到B的SYN+ACK婚被,這時候SYN會進(jìn)入重傳,應(yīng)用層通常會設(shè)置一個連接超時時間梳虽,當(dāng)這個連接超時時間溢出的時候就會報超時異常
UnknowHostException
- 通常采用域名去連接的時候址芯,域名會先通過dns解析成ip最終去用ip連接,但是在dns解析ip的時候沒有解析出ip或者解析失敗就會報這個異常窜觉,dns是采用udp協(xié)議谷炸,在Android設(shè)備上會連續(xù)連續(xù)嘗試8次,每次超時時間為5秒禀挫,因此如果dns解析超時旬陡,一共耗時40秒,也就是說:
InetSocketAddress inetSocketAddress = new InetSocketAddress(hostInfo.getHostname(), hostInfo.getPort());
這個代碼會卡40秒语婴,具體抓包信息如下:
ConnectException:network is unreachable
- 這個很明顯描孟,網(wǎng)絡(luò)不可用會報此異常
NoRouteToHostException: No route to host
- 這個是由于DHCP(Dynamic Host Configuration Protocol驶睦,動態(tài)主機(jī)配置協(xié)議,使用UDP協(xié)議)租約過期造成的匿醒,在局域網(wǎng)中场航,DHCP的主要作用就是給局域網(wǎng)中的設(shè)備分配IP,分配策略如下:
- 自動分配方式(Automatic Allocation)廉羔,DHCP服務(wù)器為主機(jī)指定一個永久性的IP地址溉痢,一旦DHCP客戶端第一次成功從DHCP服務(wù)器端租用到IP地址后,就可以永久性的使用該地址
- 動態(tài)分配方式(Dynamic Allocation)憋他,DHCP服務(wù)器給主機(jī)指定一個具有時間限制的IP地址孩饼,時間到期或主機(jī)明確表示放棄該地址時,該地址可以被其他主機(jī)使用
- 手工分配方式(Manual Allocation)竹挡,客戶端的IP地址是由網(wǎng)絡(luò)管理員指定的镀娶,DHCP服務(wù)器只是將指定的IP地址告訴客戶端主機(jī)
三種地址分配方式中,只有動態(tài)分配可以重復(fù)使用客戶端不再需要的地址此迅,也就是說動態(tài)分配的IP地址是可能被回收的汽畴,如果一臺設(shè)備分配的IP被回收了,那這臺設(shè)備的網(wǎng)絡(luò)就不可用耸序,這時候如果往再和外網(wǎng)去建立socket連接忍些,就會報NoRouteToHostException: No route to host異常,那么為了給IP續(xù)約坎怪,Android設(shè)備中會去實(shí)現(xiàn)DHCP協(xié)議罢坝,定期30分鐘去發(fā)起一個DHCP請求來更新IP信息,保持設(shè)備網(wǎng)絡(luò)可用搅窿,但是當(dāng)這個DHCP請求失敗的時候嘁酿,此時IP要是過了有效時段,那么這段時間內(nèi)的設(shè)備網(wǎng)絡(luò)是無法訪問外網(wǎng)的男应,直到DHCP請求重試成功為止
Connection Refused
- 連接被拒絕闹司,通常客戶端向服務(wù)器的指定端口發(fā)起一個TCP連接沐飘,要是服務(wù)器的并沒有監(jiān)聽這個端口游桩,此時會拒絕TCP連接,會報Connection Refused異常
TCP端口重用
- 在同一個進(jìn)程中耐朴,一個端口如果已經(jīng)被一條TCP占用借卧,那么當(dāng)?shù)诙lTCP連接還想申請使用這個端口的時候會報端口重用異常
socket read返回-1
- -1就是文件結(jié)束符(EOF),如果A和B之間有一條TCP連接筛峭,A端的socket的read的時候返回-1铐刘,那這條socket就不再有可讀取的數(shù)據(jù),造成這個-1的原因是B端的TCP發(fā)起了一個FIN影晓,可能是調(diào)用了socket的close方法
tcpdump抓包分析
tcp dup ack
- 重復(fù)的Ack镰吵,#前面的數(shù)組表示丟包的包序號檩禾,后面表示第幾次丟失,之所以會重復(fù)的Ack是可能是因?yàn)樵诰W(wǎng)絡(luò)延遲較高捡遍,或者鏈路擁塞的時候一個包重傳了多次锌订,但是重傳的這幾次最終都被收到了,在接收端第一次收到這個包的時候?qū)@個包進(jìn)行了Ack画株,然后再收到后面幾次重傳辆飘,再回復(fù)重復(fù)的Ack
tcp out of order
- 收到的包是亂序的,TCP協(xié)議確保消息必達(dá)并且順序谓传,但是TCP協(xié)議是基于IP協(xié)議的蜈项,IP報文并不確保消息的順序性,所以先發(fā)出的IP報文可能比后發(fā)的IP報文先到達(dá)续挟,這里可能是鏈路擁塞紧卒,網(wǎng)絡(luò)延遲,丟包诗祸,Client到Server有多條網(wǎng)絡(luò)路徑導(dǎo)致IP報文到達(dá)的順序發(fā)生亂序跑芳,TCP協(xié)議在收到消息包后發(fā)現(xiàn)如果順序亂了,就緩存起來暫時步拋給應(yīng)用層直颅,直到前面的消息包都收到為止博个,然后再重新組織消息的順序,拋給應(yīng)用層功偿,所以在實(shí)際場景中tcp out of order并不一定是代表異常盆佣,但是看到tcp out of order發(fā)生之后可能就懷疑鏈路是否發(fā)生擁塞,或者網(wǎng)絡(luò)延遲械荷,丟包等等來去判斷此時網(wǎng)絡(luò)是否穩(wěn)定
tcp retransmission
- TCP協(xié)議既然要保證消息必達(dá)共耍,所以在一個消息發(fā)送出去之后,就會等待對方確認(rèn)收到這個消息的Ack吨瞎,在消息發(fā)送出去之后會啟動一個定時器來檢測是否在規(guī)定時間內(nèi)有收到Ack痹兜,如果沒有收到Ack,這時候就會觸發(fā)此消息重傳颤诀,這里還涉及到RTT(消息的回顯時間)字旭,RTO(消息重傳超時),每一次消息包發(fā)送都可能(這里并不一定會觸發(fā)RTT計算着绊,要看這時候的計算RTT的定時器是否啟動谐算,如果啟動熟尉,那么這次消息包發(fā)送就不會計算RTT)會不斷的去調(diào)整計算RTT归露,然后根據(jù)計算出來的RTT,再根據(jù)指定的公式計算出RTO
- 關(guān)于超時重傳的一個疑問:當(dāng)有一個消息包正在TCP底層進(jìn)行重傳的過程中斤儿,應(yīng)用層此時再寫入數(shù)據(jù)的話剧包,那寫入的這個數(shù)據(jù)會再發(fā)送出去嗎恐锦?我的解答是:1.如果發(fā)生了超時重傳,那此時可能就存在網(wǎng)絡(luò)擁塞疆液,tcp協(xié)議針對網(wǎng)絡(luò)擁塞控制就有幾種策略一铅,Nagle算法,滑動窗口堕油,慢啟動潘飘,擁塞避免,快速重傳后快速恢復(fù)(擁塞避免)掉缺;在Nagle算法的情況下卜录,由于改算法需要等待上次消息的Ack回來之后才把后面的消息寫入到網(wǎng)絡(luò)中,所以此時應(yīng)用層寫入的數(shù)據(jù)并不會發(fā)送出去眶明;而對于滑動窗口艰毒,如果接收窗口(提供窗口)為0,那數(shù)據(jù)也不會發(fā)送出去搜囱;對于慢啟動丑瞧,慢啟動還是需要在前一條消息的Ack回來之后才允許后續(xù)消息繼續(xù)發(fā)送,擁塞窗口只是控制發(fā)送消息的大小蜀肘,防止向網(wǎng)絡(luò)中寫入過多的數(shù)據(jù)加重?fù)砣硇冢凰詰?yīng)用層如果在TCP底層有一個消息正在重傳,此時再寫入一個數(shù)據(jù)的話幌缝,此數(shù)據(jù)如果立即發(fā)送并且超時那么有可能在目前已有重傳過程中一起被發(fā)送出去(此操作需要根據(jù)當(dāng)前的接收窗口是否允許發(fā)送這么大的數(shù)據(jù)或者根據(jù)擁塞窗口是否發(fā)送這個大的數(shù)據(jù)來決定新寫入的數(shù)據(jù)是否跟著重傳一起發(fā)送出去)灸促,也有可能一直緩存這,等待上一個重傳成功收到Ack之后才寫出去
12-17 10:03:40.994 2725 2960 I SYNC-PUSH: {ConnectionService$7.onWrite--1} write [107] bytes.
12-17 10:04:02.234 2725 3052 I SYNC-PUSH: {ConnectionService$7.onWrite--1} write [7] bytes.
應(yīng)用層將107字節(jié)發(fā)寫入之后涵卵,發(fā)生了重傳浴栽,這時候在10:04:02秒又寫入7個字節(jié),我們在抓包的時候發(fā)現(xiàn)重傳并沒有把這7個字節(jié)一起發(fā)送出去轿偎,說明這個7個字節(jié)被暫時緩存起來了典鸡,此時有可能是網(wǎng)絡(luò)擁塞了,所以就不再向鏈路中發(fā)送數(shù)據(jù)避免加重網(wǎng)絡(luò)擁塞坏晦,如果此時并不是網(wǎng)絡(luò)擁塞萝玷,那么有可能這7個字節(jié)就在重傳過程中被一起發(fā)送出去
tcp fast retransmission
-
快速重傳,快速重傳是當(dāng)預(yù)測到鏈路可能存在擁塞的時候昆婿,連續(xù)收到了三次重復(fù)的Ack球碉,快速重傳之后進(jìn)入快速恢復(fù)算法(擁塞避免,cwnd擁塞窗口線性增加)
tcp previous segment not captured
- 這個是指前一個消息包還沒有收到仓蛆,后一個消息包先收到
上圖睁冬,發(fā)生tcp previous segment not captured的消息包Sequence number: 1242674817,重傳的消息包Sequence number: 1242674796看疙,但是1242674817先到了豆拨,而1242674796后到直奋,所以在收到1242674817的時候會提示有漏掉一個segment數(shù)據(jù),1242674817會緩存起來并不會馬上通知給應(yīng)用層施禾,直到1242674796到了之后一起通知給應(yīng)用層
seq脚线,ack,tsval弥搞,tsecr
- seq是消息的序號邮绿,ack是消息的確認(rèn)號,確認(rèn)號是確認(rèn)上一條消息已經(jīng)被收到攀例,并且告知發(fā)送端下一次發(fā)過來的消息的序列號
- tsval是發(fā)送端發(fā)送這條消息的時間戳斯碌,tsecr是接收到對方消息的時間戳