本質(zhì):傳輸層協(xié)議
特點(diǎn):相對(duì)于UDP惭婿,面向連接驾诈、字節(jié)流和可靠傳輸
TCP頭部結(jié)構(gòu):固定部分20字節(jié)(內(nèi)容略凤瘦,可選信息有40字節(jié),最長(zhǎng)60字節(jié))
TCP建立與關(guān)閉:(抓包過程讀值m和n都是初始為隨機(jī)值ISN)
報(bào)文段 | 方向 | 標(biāo)志位情況 | seq值 | ack值 | 狀態(tài)說明 |
---|---|---|---|---|---|
1 | A>>B | SYN | m | - | (主動(dòng)打開) SYS_SEND >> |
2 | A<<B | SYN | n | m+1 | (被動(dòng)打開 LISTEN)SYS_RCVD >> |
3 | A>>B | - | - | n+1 | ESTABLISHED >> ESTABLISHED |
4 | A>>B | FIN | m+1 | n+1 | (主動(dòng)關(guān)閉)FIN_WAIT_1 >> |
5 | A<<B | - | - | m+2 | (被動(dòng)關(guān)閉)CLOSE_WAIT >> FIN_WAIT_2 |
6 | A<<B | FIN | n+2 | m+2 | LAST_ACK >> |
7 | A>>B | - | - | n+3 | TIME_WAIT >> CLOSED |
TIME_WAIT狀態(tài)
意義:理論上報(bào)文段5是不需要的,因?yàn)閳?bào)文段6已經(jīng)包含確認(rèn)信息茬射。但是需要存在一個(gè)狀態(tài)鹦蠕,使得:
1.可靠的終止TCP連接(如果沒有報(bào)文5,那么報(bào)文6回復(fù)時(shí)A端就直接跳過TIME_WAIT進(jìn)入CLOSED狀態(tài)躲株,如果次數(shù)發(fā)生了發(fā)生了報(bào)文段7丟失的情況片部,那么報(bào)文6一直會(huì)重復(fù)發(fā)送,此時(shí)A端已經(jīng)closed所以會(huì)發(fā)送復(fù)位報(bào)文段導(dǎo)致B端錯(cuò)誤)
2.讓遲來的TCP報(bào)文have enough time to abort(使后來連接同一個(gè)ip和端口的端不會(huì)收到之前連接的報(bào)文)
持續(xù)時(shí)間:TIME_WAIT要持續(xù)2MSL才會(huì)進(jìn)入CLOSED霜定。MSL是TCP報(bào)文段在網(wǎng)絡(luò)中的最大生存時(shí)間,RFC1122的建議值是2min廊鸥。(也就是說高并發(fā)下會(huì)瘋狂占用資源- -)
復(fù)位報(bào)文段
TCP頭里的標(biāo)志位:RST
功能:通知對(duì)方關(guān)閉連接或者重新建立連接
產(chǎn)生的情況:
1.訪問了不存在的端口:此時(shí)目標(biāo)會(huì)給sender回應(yīng)一個(gè)復(fù)位報(bào)文段望浩,sender應(yīng)該關(guān)閉或者重新連接。實(shí)際上端口處于TIME_WAIT時(shí)也會(huì)收到復(fù)位報(bào)文段惰说。
2.異常終止連接:用發(fā)送復(fù)位報(bào)文段而不是發(fā)送結(jié)束報(bào)文段的方法來終止連接磨德,此時(shí)發(fā)送端排隊(duì)發(fā)送的數(shù)據(jù)會(huì)被全部丟棄。
3.處理半打開連接:一方因?yàn)楫惓6K止連接吆视,而另一方還維持著典挑,稱之為半打開狀態(tài)。半打開狀態(tài)的如果往連接里寫入數(shù)據(jù)啦吧,則對(duì)方回應(yīng)一個(gè)復(fù)位報(bào)文段您觉。
TCP交互數(shù)據(jù)流
以telnet登錄本機(jī),用shell執(zhí)行l(wèi)s命令為例授滓,下面是抓包情況:
(win值:窗口大小琳水,告訴對(duì)方本端還能接受多少字節(jié)以控制TCP流量,seq和ack第一行后都為偏移值)
報(bào)文段 | 方向 | 標(biāo)志位情況 | seq值 | ack值 | length值 | 狀態(tài)說明 |
---|---|---|---|---|---|---|
1 | A>>B | PSH | m:m+1 | n | 1 | client發(fā)送'l'字母 |
2 | A<<B | PSH | n+1:n+2 | m+1 | 1 | server確認(rèn)1并回顯字母'l' |
3 | A>>B | - | - | n+2 | 0 | client確認(rèn)2 |
4 | A>>B | PSH | m+1:m+2 | n+2 | 1 | client發(fā)送's'字母 |
5 | A<<B | PSH | n+2:n+3 | m+2 | 1 | server確認(rèn)4并回顯字母's' |
6 | A>>B | - | - | n+3 | 0 | client確認(rèn)5 |
7 | A>>B | PSH | m+2:m+4 | n+3 | 2 | client發(fā)送回車和EOF |
8 | A<<B | PSH | n+3:n+176 | m+4 | 173 | server返回ls命令的結(jié)果 |
9 | A>>B | - | - | n+176 | 0 | client確認(rèn)8 |
10 | A<<B | PSH | n+176:n+228 | m+4 | 52 | server返回一個(gè)回車+換行符+PS1環(huán)境變量 |
11 | A>>B | - | - | n+228 | 0 | client確認(rèn)10 |
因?yàn)榭蛻舳溯斎胨俣冗h(yuǎn)遠(yuǎn)小于服務(wù)器處理速度般堆,所以服務(wù)器通常使用延遲確認(rèn)(報(bào)文2,5,8,10)以減少發(fā)包數(shù)在孝。
Nagle算法了解下。
TCP 成塊數(shù)據(jù)流
考慮用FTP傳輸一個(gè)大文件淮摔,啟動(dòng)vsftpd服務(wù)器程序私沮,并執(zhí)行ftp登錄它,然后再ftp中輸入get命令從服務(wù)器上下載一個(gè)幾百m的大文件和橙,同時(shí)進(jìn)行抓包仔燕。
抓包過程可以看出,當(dāng)傳輸大塊數(shù)據(jù)時(shí)胃碾,發(fā)送方會(huì)連續(xù)發(fā)送多個(gè)TCP報(bào)文段涨享,接受方可以一次性確認(rèn)所有這些報(bào)文段。那么問題就是在確認(rèn)之前能夠連續(xù)發(fā)送多少包了仆百。
能夠連續(xù)發(fā)送的TCP報(bào)文段數(shù)量n是由確認(rèn)的接受通告窗口(win值)決定的厕隧,n=win值 *64字節(jié)(窗口擴(kuò)大因子為6時(shí)) / length值。
另外每4個(gè)TCP報(bào)文段會(huì)帶一個(gè)PSH標(biāo)志,以通知客戶端應(yīng)用盡快讀取數(shù)據(jù)吁讨,不過好像沒啥用髓迎,因?yàn)樗纖in值不為0。
帶外數(shù)據(jù)
Out of Band建丧,OOB排龄,比普通數(shù)據(jù)有更高的優(yōu)先級(jí),無視隊(duì)列立刻發(fā)送翎朱。用的不多橄维,了解即可。
TCP超時(shí)重傳
TCP要保證可靠性就必須要處理超時(shí)或者丟包的情況拴曲。
設(shè)定iperf服務(wù)器程序争舞,然后執(zhí)行telnet登錄改服務(wù)器程序,之后發(fā)送一些數(shù)據(jù)給服務(wù)器澈灼,然后斷開服務(wù)器的網(wǎng)線并再發(fā)一些數(shù)據(jù)竞川,同時(shí)進(jìn)行tcpdump抓包。
在抓包時(shí)時(shí)保留時(shí)間戳以推測(cè)TCP的超時(shí)重傳策略叁熔,因此重傳的5次報(bào)文的時(shí)間間隔分別為0.2s委乌、0.4s、0.8s荣回、1.6s和3.2s遭贸,可見TCP一共進(jìn)行5次重傳,每次的重傳超時(shí)時(shí)間都會(huì)增加一倍驹马。5次失敗之后有IP和ARP接管革砸,直到telnet客戶端放棄為止。在實(shí)例中TCP連接超時(shí)后堅(jiān)持了15min糯累。
擁塞控制
本質(zhì):一個(gè)閉環(huán)反饋控制算利,標(biāo)準(zhǔn)文檔RFC 5681。一次寫入的數(shù)據(jù)量稱為SWND(Send Window泳姐,發(fā)送窗口)效拭,由RWND(Receive Window,即win值)和CWND(Congestion Window胖秒,發(fā)送方引入的擁塞窗口)的較小值決定缎患。SWND太小導(dǎo)致網(wǎng)絡(luò)延遲,太大導(dǎo)致網(wǎng)絡(luò)阻塞阎肝。
慢啟動(dòng)和擁塞避免:CWND被初始化為IW(Intial Window挤渔,大小為2~4個(gè)SMSS,即發(fā)送者最大段大蟹缣狻)判导,此后發(fā)送端沒收到一個(gè)接受端的確認(rèn)嫉父,CWND就按照以下公式增加:CWND+=(N,SMSS),N就是包含之前未被確認(rèn)的字節(jié)數(shù)眼刃。這樣一來沒有其他條件的話绕辖,CWND會(huì)指數(shù)增加(看來慢啟動(dòng)其實(shí)并不慢)。
為了避免慢啟動(dòng)過快導(dǎo)致網(wǎng)絡(luò)阻塞擂红,需要定義一個(gè)慢啟動(dòng)門限(slow start threshold size, ssthresh)仪际。擁塞避免算法使得CWND按照線性增加,從而減緩其擴(kuò)大昵骤。RFC 5681中提到了兩種實(shí)現(xiàn)方式树碱,自行了解。最后一提变秦,當(dāng)傳輸超時(shí)或者TCP重傳定時(shí)器溢出時(shí)使用慢啟動(dòng)和擁塞避免赴恨,但是當(dāng)接收到重復(fù)的確認(rèn)報(bào)文段時(shí)將使用快速重傳和快速恢復(fù),但是第二種情況發(fā)生在定時(shí)重傳器溢出的話也當(dāng)做第一種情況處理伴栓。
如果是第一種情況,即傳輸超時(shí)雨饺,就執(zhí)行重傳并做一下ssthresh的調(diào)整(式1):
ssthresh = max(FlightSize/2, 2*SMSS)
FlightSize為已經(jīng)發(fā)送但是沒被確認(rèn)的字節(jié)數(shù)钳垮。這樣調(diào)整后CWMD將小于SMSS,也小于調(diào)整后的ssthresh额港,從而再進(jìn)入慢啟動(dòng)階段饺窿。
快速重傳和快速恢復(fù):發(fā)送端收到3個(gè)重復(fù)的確認(rèn)報(bào)文段后,就認(rèn)為擁塞發(fā)生了移斩,然后用快速重傳和快速恢復(fù)算法來處理擁塞肚医,過程如下:
1.ssthresh按照(式1)重新計(jì)算,然后立即重傳丟失的報(bào)文段向瓷,并重新設(shè)置CWND=ssthresh+3*SMSS肠套。
2.每再收到1個(gè)重復(fù)的確認(rèn)時(shí),設(shè)置CWND+=SMSS猖任,此時(shí)發(fā)送端可以發(fā)送新的TCP報(bào)文段你稚。
3.新數(shù)據(jù)被確認(rèn)時(shí),設(shè)置CWND=ssthresh
快速重傳和快速恢復(fù)完成后將恢復(fù)到擁塞避免階段朱躺。