
关于Seq和Ack的理解
一次TCP连接中的所有有效数据都会被标号, SYN报文和FIN报文也占用一个Seq号。一个TCP报文中有效数据的第一个字节的编号就是Seq号;一端使用Ack=x,表示该端已经收到来自对方所有字节号<x的数据,所以有种说法是“Ack号是发送方期待下一次接收到的有效数据的第一个字节编号,也即Seq号”
Seq号永远有效,Ack只有在ACK位置1时才有效。当且仅当在一次TCP连接中的第一个报文中,TCP头部才会出现ACK未被置1的情况。在剩余所有情况,ACK位均被置1。
实例分析
#1
TCP连接开始时,双方均有相对Seq=0,代表有效数据从编号0开始。第一个包中ACK位未被置1,所以对于客户端来说Ack编号无效(也可以认为就是0,因为没有接收到来自服务器的数据)。
#2
服务器收到客户端的SYN报文,自己也发送一个SYN报文,Seq=0代表服务器端的有效数据编号从0开始,Ack=1表示自己已经收到来自客户端的编号<1的数据,也就是说期望客户端下此的有效数据编号(即Seq号)从1开始。
#3
客户端收到SYN报文,发出ACK报文做回应。该报文Seq=1暗示有效数据编号从1开始,Ack=1暗示自己已经收到来自服务器的编号<1的数据。
#4
客户端做出http请求,注意该请求有效数据长度len=125,该报文Seq=1暗示有效数据编号从1开始,Ack不变是因为还没有接收到服务器发送的数据。
注:为什么#3中先服务器发送了ACK报文,但是#4中Seq却不+1?是因为单独的ACK报文不含有效数据,而SYN和FIN报文却算作有效数据。
#5
服务器回应ACK代表收到http请求,Seq=1是因为目前仍未发送额外的有效数据,Ack=1(第二步)+125(第四步len长度)=126代表服务器确认自己收到了来自客户端的编号<126的数据。
#6
服务器回应http请求,有效数据从Seq=1开始,长度len=226,Ack不变是因为从客户端接收到的有效数据没有增加。
#7 第一次挥手
服务端请求关闭连接,Seq=1(第六步)+226(第六步len长度)=227,Ack不变。
#8 第二次挥手
客户端回应ACK报文代表收到,Seq=1(第四步)+125(第四步)=126,Ack=1(第四步)+226(第六步有效数据长度)+1(第七步FIN报文)=228
注:也可以说228=227(第七步)+1(第七步FIN报文),但从第四步累加到第八步更有助于理解细节,两种做法完全等效。
#9 第三次挥手
客户端也发出FIN报文请求关闭连接,Seq仍不变(因为上一步的Ack不算有效数据),Ack也不变。
#10 第四次挥手
服务器收到FIN报文,做出ACK回应,Seq=Seq(第七步)+1(第七步FIN报文长度)=228,Ack=Ack(第七步)+1(第九步FIN报文长度)=127。至此双方均断开TCP连接。