一、IP首部
- Version:版本。由4比特构成,标识IP首部的版本号,IPv4或IPv6;
- IHL(Internet Hearder Length):首部长度。对于不包含Options的IP首部,长度为5个32比特,即5个4字节,总共20字节;
- Type Of Service:用来表明服务质量;
- Total Length:IP数据包总长度,即IP首部长度和数据部分的总长度;
- Identification:标识,用于分片重组。由于一般网卡的MTU(最大传输单元)是1500,超过该长度的数据报会进行分片,同一个数据报的分片Identification也相同;
- Flags:标志。包含以下三种标志:
– R:未使用,必须是0;
– DF:是否进行分片,0代表可以分片,1代表不能分片;
– MF:包被分片的情况下,0代表最后一个分片,1代表数据报中段的分片; - Fragment Offset:片偏移,用来标识每个分片相对于原始数据的位置;
- Time To Live:TTL,生存时间。实际指数据报可以中转多少个路由器,每经过一个路由器,TTL减1;
- Protocol:上层协议;
- Header Checksum:首部校验和。用来检验IP首部,确保IP数据报没有被破坏。
二、TCP首部
- Sequence Number:序列号,指发送数据的位置,每发送一次数据,就累加一次该数据的大小;
- Acknowledgement Number:确认应答序列号。指下一次应该收到的seq序列号,TCP连接过程中,通常为当前收到的seq序列号+1,数据传输过程中,通常为当前收到的seq序列号+传输的TCP数据段的长度;
- Data Offset:数据偏移,指TCP所传输的数据部分应该从TCP数据包的哪个位置开始。也可以把它当做TCP首部的长度;
- Reserved:保留位,通常设置为0;
- Control Flag:控制位,包含以下八种:
– SYN:值为1时,表示希望建立连接;
– ACK:值为1时,确认应答序列号的字段生效;
– PSH:值为1时,表示需要将收到的数据立刻发送给上层应用协议,而不是在缓冲区中排队;
– RST:值为1时,表示TCP连接出现异常,必须强制断开连接;
– URG:值为1时,表示包中有需要紧急处理的数据;
– FIN:值为1时,表示不再传送数据,希望断开连接;
– CWR、ECE - Window Size:滑动窗口大小,用于通知从相同TCP首部的确认应答序列号所指位置开始能够接收的数据大小;
- Checksum:校验和;
- Urgent Pointer:紧急指针,仅在控制位URG为1时有效。
三、TCP三次握手和四次挥手
3.1、三次握手
- 第一次握手,A发送数据包,将SYN标志位置为1,表示希望建立连接,同时产生序列号seq=x。A的状态变化:
CLOSED->SYN-SENT
; - 第二次握手,B接收到来自A的数据包,将ACK标志位置为1作为应答,并发送确认应答序列号ack=x+1,表明希望A发送的下一个数据包序列号应该为x+1。同时将SYN置为1,表示也希望建立连接,同时产生序列号seq=y。B的状态变化:
LISTEN->SYN-RCVD
; - 第三次握手,A接收到来自B的应答,将ACK标志位置为1作为应答,并发送确认应答序列号ack=y+1。同时会发送序列号seq=x+1。A的状态变化:
SYN-SENT->ESTABLISHED
。
B收到来自A的应答数据包,检查A发送的序列号seq和应答序列号ack的值是否正确。如果正确,TCP连接建立。B的状态变化:SYN-RCVD->ESTABLISHED
。
如果在第三次握手过程中,B没有成功收到来自A的应答,将会重新发送第二次握手时的SYN+ACK。重传5次(由/proc/sys/net/ipv4/tcp_synack_retries控制,默认值是5)都没有接收到应答时,会关闭连接。
而A在发送完确认应答后,认为连接已经建立。当A向B发送数据,会收到来自B的RST数据包。
注意:
1)TCP连接中,每次发送数据包都应该包含序列号seq,并按1递增;
2)SYN和ACK标志位都是1的状态,发生在TCP连接建立的第二次握手时。
3.2、四次挥手
- 第一次挥手,假如A主动断开连接。将FIN标志位置为1,表示希望断开连接,同时产生序列号seq=u。A的状态变化:
ESTABLISHED->FIN-WAIT-1
; - 第二次挥手,B收到来自A的数据包,但是B的数据还没有传输完成,只给A返回确认应答包:ACK标志位置为1,确认应答序列号ack=u+1,并产生序列号seq=v。B的状态变化:
ESTABLISHED->CLOSE-WAIT
。
A收到来自B的确认应答,状态变化:FIN-WAIT-1->FIN-WAIT-2
; - 第三次挥手,B的数据发送完成后,将FIN标志位置为1,表示可以断开连接,产生序列号seq=w。同时作为对A的应答数据包,将ACK标志位也置为1,并发送确认应答序列号ack=u+1。两次挥手的序列号seq=v和seq=w可能相同,取决于两次挥手之间是否有其他数据传输。B的状态变化:
CLOSE-WAIT->LAST-ACK
; - 第四次挥手,A收到来自B断开连接的数据包,将ACK标志位置为1,发送确认应答序列号ack=w+1,并发送序列号seq=u+1。A的状态变化:
FIN-WAIT-2->TIME-WAIT
,等待2MSL时间后,连接关闭。
B收到来自A的确认应答,检查序列号seq和确认应答序列号ack的值,检查正确,连接关闭。
注意:
- 如果服务端一直处于CLOSE-WAIT状态,通常是由程序引起的;
- 关闭连接,为什么要四次挥手?因为TCP连接基于全双工模式,连接是双向的;
- TIME-WAIT为什么要等待2MSL?为了可靠地关闭全双工连接;老的重复分节在网络上消失需要时间;
- TIME-WAIT通常出现在主动关闭连接的一方;
- MSL:最长分节生存时间。Linux通常为30秒。
TIME-WAIT相关的参数:
- /proc/sys/net/ipv4/tcp_tw_recycle:是否开启TCP连接中TIME-WAIT sockets的快速回收,1表示开启,0表示关闭,默认为0。当客户端处于NAT环境或者负载均衡器上不能启用该参数;
- /proc/sys/net/ipv4/tcp_tw_reuse:是否允许将TIME-WAIT sockets重新用于新的TCP连接,1表示开启,0表示关闭,默认为0。开启时,必须相应地启用/proc/sys/net/ipv4/tcp_timestamps;
- /proc/sys/net/ipv4/tcp_timestamps:根据时间戳判断报文到达的顺序。
- /proc/sys/net/ipv4/tcp_max_tw_buckets:系统接受的最大timewait sockets数目。如果超过此数的话,TIME-WAIT socket会被立即断开并且显示警告信息。