TCP 学习笔记 --- Kindda Hu
08.12.15 [email protected]
Reference: TCP/IP详解卷一/ RFC793 /
以下是个人总结, 语言方面若有看不习惯请见谅. 还有几点不明白之处请指教,请参考#Issues to be comfired. 若本人总结有错误之处,请各位及时指出并告知.
########## TCP Header ###################
TCP Header Format 20Bytes
########## TCP 基本传输流程#################
Sender A ----------------> Receiver B
Step 1:Start 3-hands shake
SYN seq j ,mss ,win
a, ------------------------->
SYN seq q,mss,win; ACK ack j+1
b, <-------------------------
seq j+1 ACK ack q+1
c, ------------------------->
Step 2: Data flow
2.1 数据不需要分组,
seq j+1, ack NO (Length),
d, ------------------------->
ack (j+length+1), win size
e, <-------------------------
2.1 数据包进行分组转发,绝大多数都需要如此发送:
seq j+1, ack seq no (Length),
f, ------------------------->
ack (j+length+2), win size
g, <-------------------------
seq j+length,ack no(length),win size,
h, ------------------------->
seq (j+length+length),ack no(length),win size,
i, ------------------------->
ack j+length+1;win size
j, <-------------------------
ack j+length+length+1;
k, ------------------------->
.................
Step 3, Close. FIN 4 hands shake
Fin seq j',
l ------------------------->
ACK seq j'+1
m <-------------------------
Fin seq q'
n <-------------------------
ACK seq q'+1
o ------------------------->
Step1 , TCP 建立, 3次握手; 下面为正常的TCP session建立过程;
a. A主动建立TCP连接, 发送SYN 包, seq no为当前定时器给的值j(参见关于SEQ NO),宣称自己的MSS, window size;
b. B回复ACK, ack no = j+1,并同时发SYN包给发A, seq no为B自身定时器的值q, 并宣称自己的mss和win size;
c. A收到B发来的SYN包后回复ACK, ack no=q+1;
ps: Step1为标准的正常TCP session建立流程,还有一些非正常现象,如A和B同时向对方发送SYN包,则通过4次握手只建立一个TCP session;
Step2, 数据传输, TCP session建立后,A给B发送数据包
2.1 数据不需要分组传输,每个数据包单独传输.
d. A给B发送数据包,Seq no为j+1,和步骤c中的seq no相同, 因为A并没有收到B发送新的ack no,length为数据的长度(因为需要发 送的数
据字节长度小于MSS和win size,所以不需要分段), (参考关于数据包分组(分段)传输标准);
e. B收到数据后给A回复ACK, ack no为j+1+length;
ps:
2.2 数据需要进行分组传输
f. A给B发送一个数据报文,seq no为j+1, 长度为length;
g.B给A刚才的data报文回复ACK, ack no为j+1+length+1;
h.A收到B对于刚发送data包的ack后, 使用其ack no作为seq no发送数据,length为l';
i. A使用seq no为 j+1+length+1+L'再次发送数据报文; (连续发送两个数据包. 发送方接收到一个ack则增加一个发送数据包.因为使用了慢启动. 详情
请参照 关于慢启动)
j. B收到2个data包后回复ack包(根据网络情况和b决定. 只回复一个ack或者针对每个data都回复ack. 具体参考关于接收方什么时候回复ACK报文)
k. 很步骤h类似, 这次发送的data数根据收到的ack报文来决定,收到n个则再增加n个;
Step3, 结束TCP Session,
TCP session的结束类似于TCP session的建立(只不过将给对方的ack和自己的fin请求区分开了), 需要分别想对方发送FIN请求,并得到对方的ack后
才close掉此链接;
l. 当数据发送完成后,发送方A给接收方B发送FIN结束请求, seq为j';
m.B收到Fin后,回复ACK报文给A;
n.B给A发送FIN请求结束报文;
o.A收到ACK后结束对B的TCP 状态调整为closed; 并在收到B发送的Fin后,回复ACK给B; B在收到ack后将自己对于A的tcp状态调整为closed;
ps: 有的TCP版本中,结束时只进行单方面结束,即两次握手,A给B发FIN,B回复ACK,但是不发送Fin请求;
######### TCP 状态变迁 ###############
# 如下图为TCP状态机图
#如下图为正常的T C P连接的建立与终止过程中,客户与服务器所经历的不同状态。
Ps: 主动结束的需要先进入Time-wait状态后经过2MSL后进入Closed状态;
被动结束的,只需要在LAST-ACK状态中收到ACK回复即可进入Clolse状态;
因为提出主动结束的大都为客户端,所以服务器被动结束,直接进入Closed状态.
### 下面为TCP 各种状态的具体说明
A connection progresses through a series of states during its
lifetime. The states are: LISTEN, SYN-SENT, SYN-RECEIVED,
ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK,
TIME-WAIT, and the fictional state CLOSED.
CLOSED is fictional because it represents the state when there is no TCB, and therefore,no connection. Briefly the meanings of the states are:
LISTEN - represents waiting for a connection request from any remote
TCP and port. 监听状态;
SYN-SENT - represents waiting for a matching connection request
after having sent a connection request. Syn已经发出状态;
SYN-RECEIVED - represents waiting for a confirming connection
request acknowledgment after having both received and sent a
connection request. 收到SYN,回复ack并发送SYN包;
ESTABLISHED - represents an open connection, data received can be
delivered to the user. The normal state for the data transfer phase
of the connection. 收到针对自己发出SYN包的ACK报文,则变成Estab状态;
FIN-WAIT-1 - represents waiting for a connection termination request
from the remote TCP, or an acknowledgment of the connection
termination request previously sent. 主动结束中,发送FIN报文,并等待ACK或者Fin的阶段;
FIN-WAIT-2 - represents waiting for a connection termination request
from the remote TCP. 主动结束中,接收到针对自己发出FIN包的ACK.并等待对方FIN包的阶段;
CLOSING - represents waiting for a connection termination request
acknowledgment from the remote TCP. 主动结束中,在FIN-Wait1状态,等待对方ACK包的过程中收到对方的主动结束请求FIN包,则进入CLOSING阶段;
TIME-WAIT - represents waiting for enough time to pass to be sure
the remote TCP received the acknowledgment of its connection
termination request.
CLOSE-WAIT - represents waiting for a connection termination request
from the local user.被动结束中,收到对方的FIN请求,回复ACK报文的阶段;
LAST-ACK - represents waiting for an acknowledgment of the
connection termination request previously sent to the remote TCP
(which includes an acknowledgment of its connection termination
request). 被动结束中,在COLSE-WAIT的基础上,发送FIN请求后,等待ACK报文的阶段 ;
CLOSED - represents no connection state at all. 主动结束时,由Time-WAIT经过2msl到达Colsed; 被动结束时, 由LAST-ACK报文收到最后的ack后进入的状态.
################## 相关概念 ###########################3
sender 相关概念:MTU,MSS,window size 的左边, Cwnd(congetion window size)和 慢启动门限ssthresh, RTT, RTO,
Receiver 相关概念: MRU,MSS,window size的右边, window size,buffer size, tcp 处理进程, 回复ack. window size , buffer size , seq no, ack no
#关于PUSH标记
若接收方收到一个带PSH标志的包,则立即提交到TCP进程进行处理,并回复ACK. 若数据包中不带PSH标记, 则是由分组到齐或者buffer size到一定程度上将数据
提交到TCP处理进程中.
#关于SEQ NO
seq NO 为数据包发送的序列号, TCP 报头中包括Seq no 和 ack seq NO,分别占4个字节, 所以其值为[ 0- 65535x65535].
第一个syn包中的seq no值由发送方的定时器决定. Seq No 由一个定时器维护着,每隔4ms, seq+1, 达到最大值后继续冲最小值开始循环, 如此反复;
数据传输时的seq no (我认为)为ack回复的ack no为准, = sender's seq +1;也可是发送方的原seq no+Length+1; (RFC793中如此规定,但是也有不同实现的.)
#关于DATA Offset
数据开始的偏移位数,就是说从x个字节开始为数据, x之间的为TCP Header,所以也可解释为TCP 头部的长度. 但是x=nx4;如offset这4个bit为1000的话,则10进制为8,所以tcp header长度为8x4=32;
###### 关于定时器 ##########
## 关于坚持定时器 Persist Timer:
即窗口大小检测定时器, 发送方通过该定时器定期查询接收方窗口状态. 防止一下情况产生,
a, receever win size为0,并通知sender,sender 暂停发送报文,并等待窗口更新报文ack的到来;
b, receiver 窗口更新, 发送ack通知sender,但是该ack包被丢失.
c, 则出现了, sender 等待win size更新报文,不发送数据; receiver 等待sender发送新的数据的 双方互等的情况发生.
persist timer 在收到win size为0的ack包时被启动,然后每隔一段(5s)时间进行查询.
receiver 的window size 需要从从0更新到大于1/2的buffer size的时候,才告知sender,否则仍然宣称win = 0 ;
## 关于保活定时器 Keepalive Timer:
可以理解为TCP Session timeout keepalive time, 当建立好的tcp session处于空闲时,双方都处于Established状态,保活定时器则可以在一段时间以后自动停
止该tcp session. 但是RFC和有的TCP版本并不支持该定时器.
## 关于2MSL 定时器
##关于判断是否分组的标准:
首先理解下面几个概念: 需要传输的数据字节数, MSS,MTU, Window size;
#关于需要传输的数据字节数.
既被传输数据的字节个数. (如"Hello World"为10个字节.若每次只发送一个hello world,则每次为10个字节; 若一次发送200个hello word,则需要传输的字节数
为2000个字节;)
#关于MSS/MTU/WINDOW SIZE则参考关于MSS,关于MTU和关于Window size;
#关于MTU
MTU 为最大传输单元,基于不同的链路层的. Ehternet MTU 为1518, SLIP为259, 所以相对为IP层来说,MTU= 1518-18(DMAC 6+SMAC 6+
TYPE/LENGTH 2+ CRC 4)= 1500; 相对于PPPoE来说,MTU= 1492=1500-8(PPP);
#关于MSS
MSS 是TCP协议里面的一个概念,为发送端最大发送的TCP报文中数据字段的大小,必须小于MTU,通常为 1460=
MTU-IPHead-TCPhead=1500-20-20=1460;
若A-B都在同一网段,则MSS为1460,若不在同一网段,而且程序没有指定的话,使用默认536;
MSS一般在TCP session建立阶段 三次握手时宣称和协商.
#window size
window size 接收端用来申明自己可以接收到的数据大小为窗口; 接收端用此来处理数据拥塞;
数据传输时, 窗口是滑动的, 可以理解为窗口大小为从A到B,则A代表窗口的左边, B代表窗口的右边, 所以Window size == B-A; 在传输过程中B和A都向后滑动,
当B=A时, 则window size == 0, 接收方此时不能接收任何数据, 并通知发送方让其停止发送数据, 当窗口大小更新后,发送ack通知sender告知window 大小,让
sender继续发送数据.
发送端左边A向右移动,是因为受到接收端的ack包,并将左边A移动到ack no的地方.
接收端window size右边B向右移地取决于, 接收端进程处理tcp数据并释放缓存的能力。 当缓存没有释放完全时,接收端则通过ack给发送端通告当前window
size的大小,待恢复或者变大时,发ack包通知, ack no和之前的ack包中的no 相同。 所以说buffer可以大于缓存。
接收方回复ACK的时机 取决于接收方window size的大小(接收方在发送一个A C K前不必等待窗口被填满)和接收到的包中是否带有PUSH标记.)?
下面说一下我对于什么时候需要对数据包分段的理解:
比如说一个正常的数据传输, MSS=1460,MTU=1500,Win size=65535; 当前win size为B通告的为win size'时,
1, 当要发送数据字节个数<MSS;且又<win size' 时; 不需要分组发送; 如发送hello word 或者通过telnet登录时传输user/password的报文;
2, 当要发送数据字节数>MSS;且又>win size'时, 则需要进行分组发送;如ftp传输大文件,或者一次传输200个hello world(注意:一次发送200个hello world和发
送200次hello word是不一样的. 前者需要分组,2个date报文搞定(length分别是1460+540)和一个ack报文;而后者则需要200个date报文(每个length=10),和
x(有时为200个,有时为x个,请参考关于接收方什么时候回复ACK报文)个ack报文.);
##关于如何决定是否重发数据包.(如何界定包已经丢失并重传?)
1,RTO超时;
2,连续收到3个相同Seq no的ack包,发送方则认为丢包.
#### TCP 对分组包丢失的处理 #########
当分组传输的数据被丢失后, 接收端通过对收到的数据进行处理发现后,必须发送ack报文通知发送方重新发送.
因为TCP无法告知对方缺少那一段,所以采用发送方将自己最后一个成功回复的ack包发送给对方的方式,来告诉对方应该从该seq no处将数据包进行重发.
发送方连续收到3个相同的ACK时, 则认为有包被丢弃,并重传自那个序号起的一段报文.
当接收方处于通知对方丢包并且在等待丢失包到来的状态时, 对收到的数据包只进行保存,不会上传到进程进行处理.
当接收方收到丢失包且发现没有其他丢包时, 将缓存的数据全部提交给进程进行处理.
# 慢启动和拥塞避免
Congetion window 发送端每次发送数据包的个数大小,当cwnd<= ssthresh时,每当收到一个ack,cwnd+1; 当cwnd>ssthersh时,则每次增
加1/cwnd,则cwnd=cwnd+1/cwnd. 发送方用此来进行数据拥塞的处理.
## 关于重传超时定时器 Retransmission TimeOut / RTT :
RTO 为超时重传时间. 当RTO时间内未收到对方的ack,则认为超时,重发数据包;
而RTO值是有RTT计算出来, RTT 为往返时间, 为发送方发出一个seq no的报文,到收到该报文ack 回复的时间段.由于网络流量变化,所以TCP需要跟踪这些变化,
并算出相应的值; 所以TCP中判断是否超时,重传最主要的就是要进行RTT的计算.
sender 每次发送数据要先检测RTT 测量定时器是否被启动,若没有的话则启动该定时器, 若已经启动的话则不更新.
因为TCP中ack和seq no的回复并不可能是一一对应,所以需要算法来计算RTT的值;
### Issues to be confirmed #####
1, 接收方什么时候会将buffer中的数据提交到TCP进程当中去?
包中带psh标记, buffer 到什么程度? 还是等分组全部收到? 或者自己有什么定时器?
2, TCP 不对ack报文进行确认,只对带有带有数据的ack报文进行确认. 应该如何理解!!????????
3, RTO 本身有定时器? rtt测量定时器!? 是否是每次发送方发送数据前要确认启动的定时器?
4,关于接收方B什么时候回复ACK报文?
5,关于2MSL 定时器