TCP包头结构和TCP的三次握手、四次挥手

TCP包头结构

TCP是一种面向连接的、可靠的、基于字节流的传输层通讯协议,当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据量切割成适当长度的报文段,最大传输段大小(MSS)受该最大传输单元MTU限制,之后TCP把数据包传给网络层,以此向下层封装(OSI七层模型),然后发送到对端

  • 第一行:占两个字节,传输层协议将本机的端口和目标端口进行封装,端口号取值范围0-65535
  • 第二行 序号:占四个字节,将一串数据包发送到对端,对端可能不是顺序接收数据包,那么对端就会使用序号进行排序然后再组成完整数据
  • 第三行 确认序号:占四个字节向对端表示序号已收到,可以给下一个序号了
  • 第四层
    • 数据偏移/首部长度:占4个字节,TCP报文段的数据起始位置距离TCP报文段的起始处有多远
    • 保留:占6个字节,保留为今后使用,但目前为0
    • 标志位
      • URG紧急标记位:为1时表示紧急指针字段有效,告诉对端次报文段有紧急数据,应尽快处理
      • ACK确认标记位:为1时,确认号字段才有效
      • PSH:为1表示数据段不再缓存区等待优先处理,告诉对端尽快的交付接收的程序
      • RST断开连接标记位:为1时表示TCP连接出现严重差错,必须释放连接,然后重新建立连接
      • SYN请求标记位:为1时表示连接请求或连接接收报文
      • FIN结束标记位:用来释放连接,为1表示报文段发送端数据完毕,要求释放运输连接
  • 第五行 校验和:检验和字段检验的范围包括首部和数据这两部分,二层使用循环冗余算法(CRC),四层使用反码相加法。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部
  • 第五行 紧急指针:占16位,支出此报文段中的紧急数据有多少个字节
  • 第六行 选项:长度可变,TCP最初规定了一种选项,即最大报文段长度MSS,会通知对端能接收多少个数据字节
  • 第六行 填充:为了整个首部长度是4字节的整倍数

TCP三次握手

三次握手(Three-way Handshake)是指建立TCP连接时,需要客户端和服务端总共发送三次包
image
第一次握手:客户端向服务端发送连接请求报文SYN,等待服务器回应,此时报文中的syn标志位等于j
第二次握手:服务器收到客户端的连接请求包SYN,将客户端的请求包放入到自己的未连接队列,此时服务端需要发送两个包给客户端
1、向客户端发送自己收到连接请求的确认包ACK,向客户端表明已经知道了连接请求,此时ACK=j+1,j是客户端syn发送过来的
2、向客户端发送连接询问请求包SYN,询问客户端自己是否已经准备好建立连接,此时SYN=k
即在第二次握手时服务器向客户端发送ACK(ack=j+1)和SYN(syn=k)包,此时服务器进入SYN_RECV状态。
第三次握手:客户端收到服务端发来的ACK和SYN报文,知晓了服务端同意连接,此时需要发送连接已建立的消息给服务器
1、向服务端发送连接建立的确认包ACK,回应服务器的SYN(SYN=k)。此时ACK=k+1,k是第二次握手时服务端发送的SYN
2、ACK包发送完毕后,服务器收到后,此时服务器与客户端进入ESTABLISHED状态,开始通信

为什么不能只两次握手?

三次握手的目的:消除旧有连接请求的SYN消息对新连接的干扰,同步连接双方的序列号和确认号并交换TCP 窗口大小信息。
设想:如果只有两次握手,那么第二次握手后服务器只向客户端发送ACK包,此时客户端与服务器端建立连接。在这种握手规则下: 
假设:如果发送网络阻塞,由于TCP/IP协议定时重传机制,B向A发送了两次SYN请求,分别是x1和x2,且因为阻塞原因,导致x1连接请求和x2连接请求的TCP窗口大小和数据报文长度不一致,如果最终x1达到A,x2丢失,此时A同B建立了x1的连接,这个时候,因为AB已经连接,B无法知道是请求x1还是请求x2同B连接,如果B默认是最近的请求x2同A建立了连接,此时B开始向A发送数据,数据报文长度为x2定义的长度,窗口大小为x2定义的大小,而A建立的连接是x1,其数据包长度大小为x1,TCP窗口大小为x1定义,这就会导致A处理数据时出错。
很显然,如果A接收到B的请求后,A向B发送SYN请求y3(y3的窗口大小和数据报长度等信息为x1所定义),确认了连接建立的窗口大小和数据报长度为x1所定义,A再次确认回答建立x1连接,然后开始相互传送数据,那么就不会导致数据处理出错了。

抓包查看TCP三次握手过程

  • 机器A IP:192.168.56.1
  • 机器B IP:192.168.56.81
    在机器B上抓包,Flags是标志位[S]表示SYN,[.]一般表示这是一个单一的ack确认包
root@linx:~# tcpdump -i eth1 -S tcp port 11234 -nn 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
# 第一次  机器a发给机器b seq 2025245480   
17:58:19.383310 IP 192.168.56.1.37214 > 192.168.56.80.11234: Flags [S], seq 2025245480, win 64240, options [mss 1460,sackOK,TS val 2634461862 ecr 0,nop,wscale 7], length 0
# 第二次  机器b发给机器a seq 1293924890  ack 2025245481
17:58:19.383362 IP 192.168.56.80.11234 > 192.168.56.1.37214: Flags [S.], seq 1293924890, ack 2025245481, win 28960, options [mss 1460,sackOK,TS val 99607 ecr 2634461862,nop,wscale 7], length 0
# 第三次 机器a发给机器b  ack 1293924891
17:58:19.383710 IP 192.168.56.1.37214 > 192.168.56.80.11234: Flags [.], ack 1293924891, win 502, options [nop,nop,TS val 2634461863 ecr 99607], length 0

TCP四次挥手

四次挥手表示TCP的终止过程,断开TCP连接时需要客户端和服务端总共发送4报文确认连接断开
image
挥手请求可以是客户端或服务端

第一次挥手:客户端发起挥手请求,发送标志位FIN标志位的报文,设置序号为seq,此时客户端进入FIN_WAIT_1状态,表示客户端没有数据发送给服务端了
第二次挥手:服务端收到客户端带有FIN标志位的报文,向客户端返回一个带有ACK标志位的报文段,ack值设为客户端发来的seq值+1,客户端此时进入FIN_WAIT_2状态,服务端告诉客户端,我确认并同意你的关闭请求
第三次挥手:服务端向客户端发送带有FIN标志位的报文段,并设置序号seq,请求关闭连接,此时客户端进入LAST_ACK状态
第四次挥手:客户端向服务端发送带有ACK的报文,ACK值为服务端发来的seq值+1,然后客户端进入TIME_WAIT状态,服务端收到后,关闭连接,此时客户端等待2MSL的时间后依然没有收到回复,则证明服务端已经正常关闭,客户端也紧跟关闭连接

为什么连接的时候是三次握手,关闭的时候却是四次握手?
建立连接时因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。所以建立连接只需要三次握手。

由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式。这就意味着,关闭连接时,当客户端发出FIN报文段时,只是表示客户端告诉服务端数据已经发送完毕了。当服务端收到FIN报文并返回ACK报文段,表示它已经知道客户端没有数据发送了,但是服务端还是可以发送数据到客户端的,所以服务端很可能并不会立即关闭SOCKET,直到服务端把数据也发送完毕。当服务端也发送了FIN报文段时,这个时候就表示服务端也没有数据要发送了,就会告诉客户端,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么要等待2MSL?
MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。有以下两个原因:

1.保证TCP协议的全双工连接能够可靠关闭
由于IP协议的不可靠性或者是其它网络原因,导致了Server端没有收到Client端的ACK报文,那么Server端就会在超时之后重新发送FIN,如果此时Client端的连接已经关闭处于CLOESD状态,那么重发的FIN就找不到对应的连接了,从而导致连接错乱,所以,Client端发送完最后的ACK不能直接进入CLOSED状态,而要保持TIME_WAIT,当再次收到FIN的收,能够保证对方收到ACK,最后正确关闭连接。

2.保证连接的重复数据从网络中小时
如果Client端发送最后的ACK直接进入CLOSED状态,然后又再向Server端发起一个新连接,这时不能保证新连接的与刚关闭的连接的端口号是不同的,也就是新连接和老连接的端口号可能一样了,那么就可能出现问题:如果前一次的连接某些数据滞留在网络中,这些延迟数据在建立新连接后到达Client端,由于新老连接的端口号和IP都一样,TCP协议就认为延迟数据是属于新连接的,新连接就会接收到脏数据,这样就会导致数据包混乱。所以TCP连接需要在 TIME_WAIT状态等待2倍MSL,才能保证本次连接的所有数据在网络中消失。

抓包看TCP四次挥手过程

  • 机器A IP:192.168.56.1
  • 机器B IP:192.168.56.81
    在机器B上抓包,Flags是标志位[S]表示SYN,[.]一般表示这是一个单一的ack确认包
root@linx:~# tcpdump -i eth1 -S "tcp port 11234 and host 192.168.56.1 and (tcp[tcpflags] & (tcp-fin|tcp-ack) != 0)" -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
18:45:02.020996 IP 192.168.56.1.60470 > 192.168.56.80.11234: Flags [F.], seq 3375083939, ack 1301821916, win 502, options [nop,nop,TS val 2637264502 ecr 797450], length 0
18:45:02.021188 IP 192.168.56.80.11234 > 192.168.56.1.60470: Flags [.], ack 3375083940, win 227, options [nop,nop,TS val 800267 ecr 2637264502], length 0
18:45:02.021446 IP 192.168.56.80.11234 > 192.168.56.1.60470: Flags [F.], seq 1301821916, ack 3375083940, win 227, options [nop,nop,TS val 800267 ecr 2637264502], length 0
18:45:02.021586 IP 192.168.56.1.60470 > 192.168.56.80.11234: Flags [.], ack 1301821917, win 502, options [nop,nop,TS val 2637264503 ecr 800267], length 0
posted @ 2025-04-16 00:02  夏凉浮生  阅读(65)  评论(0)    收藏  举报