root@python:~# tcpdump -n -S tcp port 5009 # -S 参数的目的是得到ack的绝对值,不加该参数,第三次握手的ack为相对值1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 17:35:43.707223 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [S], seq 267775201, win 8192, options [mss 1452,nop,wscale 2,nop,nop,sackOK], length 0 **客户端发起请求,第一次握手** 17:35:43.707299 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [S.], seq 3046340720, ack 267775202, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0 17:35:43.729057 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046340721, win 16698, length 0 **三次握手结束** 17:35:43.778243 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775202:267775428, ack 3046340721, win 16698, length 226 **开始传送数据** 17:35:43.778299 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775428, win 237, length 0 17:35:43.780225 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046340721:3046343625, ack 267775428, win 237, length 2904 17:35:43.780254 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [P.], seq 3046343625:3046343827, ack 267775428, win 237, length 202 17:35:43.802585 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046343827, win 16698, length 0 17:35:43.803603 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775428:267775619, ack 3046343827, win 16698, length 191 17:35:43.803988 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [P.], seq 3046343827:3046343878, ack 267775619, win 245, length 51 17:35:43.825824 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775619:267775895, ack 3046343878, win 16685, length 276 17:35:43.865696 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775895, win 254, length 0 17:35:44.314454 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046343878:3046346782, ack 267775895, win 254, length 2904 17:35:44.314472 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046346782:3046349686, ack 267775895, win 254, length 2904 17:35:44.314477 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046349686:3046352590, ack 267775895, win 254, length 2904 17:35:44.314482 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [P.], seq 3046352590:3046352839, ack 267775895, win 254, length 249 17:35:44.336458 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046352839, win 16698, length 0 17:35:44.402718 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775895:267775926, ack 3046352839, win 16698, length 31 17:35:44.402758 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775926, win 254, length 0 17:35:44.402869 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [F.], seq 3046352839, ack 267775926, win 254, length 0 **四次挥手开始** 17:35:44.404033 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [F.], seq 267775926, ack 3046352839, win 16698, length 0 17:35:44.404047 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775927, win 254, length 0 17:35:44.424589 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046352840, win 16698, length 0 **四次挥手结束**
S=SYN 发起链接标志。
P=PUSH 传送数据标志。
F=FIN 关闭链接标志。
ACK 表示确认包。
RST=RESET 异常关闭链接。
. 表示没有任何标志。html
客户端A,服务器B,初始序号seq,确认号ack
初始状态:B处于监听状态,A处于打开状态
A -> B : seq = x (A向B发送链接请求报文段,A进入同步发送状态SYN-SENT)
B -> A : ack = x + 1,seq = y (B收到报文段,向A发送确认,B进入同步收到状态SYN-RCVD)
A -> B : ack = y+1 (A收到B的确认后,再次确认,A进入链接状态ESTABLISHED)
链接后的状态:B收到A的确认后,进入链接状态ESTABLISHEDpython
A -> B : seq = u (A发出链接释放报文段,进入终止等待1状态FIN-WAIT-1)
B -> A : ack = u + 1,seq = v (B收到报文段,发出确认,TCP处于半关闭,B还可向A发数据,B进入关闭等待状态WAIT)
B -> A : ack = u + 1,seq = w (B重复发送确认号,进入最后确认状态LAST-ACK)
A -> B : ack = w + 1,seq = u + 1 (A发出确认,进入时间等待状态TIME-WAIT)
通过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态缓存
三次握手的最主要目的是保证链接是双工的,可靠更多的是经过重传机制来保证的。 这是由于服务端在LISTEN状态下,收到创建链接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭链接时,当收到对方的FIN报文时,
仅仅表示对方再也不发送数据了可是还能接收数据,咱们也未必所有数据都发送给对方了,因此咱们不能够当即close,也能够发送一些数据给对方后,
再发送FIN报文给对方来表示赞成如今关闭链接,所以,咱们的ACK和FIN通常都会分开发送。服务器
TCP 链接的每一端都必须设有两个窗口——一个发送窗口和一个接收窗口。TCP 的可靠传输机制用字节的序号进行控制。TCP 全部的确认都是基于序号而不是基于报文段。
发送过的数据未收到确认以前必须保留,以便超时重传时使用。发送窗口没收到确认不动,和收到新的确认后前移。
发送缓存用来暂时存放: 发送应用程序传送给发送方 TCP 准备发送的数据;TCP 已发送出但还没有收到确认的数据。
接收缓存用来暂时存放:按序到达的、但还没有被接收应用程序读取的数据; 不按序到达的数据。网络
RST表示链接重置,用于关闭那些已经没有必要继续存在的链接。通常状况下表示异常关闭链接,区别与四次分手正常关闭链接。socket
大多都写开启net.ipv4.tcp_tw_recycle这个开关,能够快速回收处于TIME_WAIT状态的socket(针对Server端而言)。
而实际上,这个开关,须要net.ipv4.tcp_timestamps(默认开启)这个开关开启才有效果。
更被提到却很重要的一个信息是:当tcp_tw_recycle开启时(tcp_timestamps同时开启,快速回收socket的效果达到),对于位于NAT设备后面的Client来讲,
是一场灾难——会导到NAT设备后面的Client链接Server不稳定(有的Client能链接server,有的Client不能链接server)。
也就是说,tcp_tw_recycle这个功能,是为“内部网络”(网络环境本身可控——不存在NAT的状况)设计的,对于公网不宜使用。tcp