一、TCP三次握手、四次挥手
TCP(Transmission Control Protocol) 传输控制协议
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
位码即tcp标志位,有6种标示:SYN(synchronous建立联机) 、ACK(acknowledgement 确认)、 PSH(push传送) 、FIN(finish结束) 、RST(reset重置) 、URG(urgent紧急)、Sequence number(顺序号码)、 Acknowledge number(确认号码)
第一次握手:主机A发送位码为SYN=1,以及随机产生初始 seq number=X 的数据包到服务器,主机B由SYN=1知道,A要求建立联机;
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq number +1),SYN=1,ACK=1,随机产生 seq number =Y 的包
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码 ACK 是否为1,若正确,主机A会再发送ack number=(主机B的seq number+1),ACK=1,主机B收到后确认seq number值与ACK=1则连接建立成功。
完成三次握手,主机A与主机B开始传送数据。
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器 进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据.
实例:
IP 192.168.1.116.3337 > 192.168.1.123.7788: S 3626544836:3626544836
IP 192.168.1.123.7788 > 192.168.1.116.3337: S 1739326486:1739326486 ack 3626544837
IP 192.168.1.116.3337 > 192.168.1.123.7788: ack 1739326487,ack 1
第一次握手:192.168.1.116发送位码SYN=1,随机产生seq number=3626544836的数据包到192.168.1.123,192.168.1.123由SYN=1知道192.168.1.116要求建立联机;
第二次握手:192.168.1.123收到请求后要确认联机信息,向192.168.1.116发送ack number=3626544837,SYN=1,ACK=1,随机产生seq number=1739326486的包;
第三次握手:192.168.1.116收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ACK是否为1,若正确,192.168.1.116会再发送ack number=1739326487,ACK=1,192.168.1.123收到后确认seq number=seq number+1,ACK=1则连接建立成功。
Wireshark 抓包图解:
第一次握手的标志位(图1)
我们可以看到标志位里面只有个同步位,也就是在做请求(SYN)
第二次握手的标志位(图2)
我们可以看到标志位里面有个确认位和同步位,也就是在做应答(SYN + ACK)
第三次握手的标志位(图3)
我们可以看到标志位里面只有个确认位,也就是再做再次确认(ACK)
一个完整的三次握手也就是 请求---应答---再次确认
在Google Groups的TopLanguage中看到一帖讨论TCP“三次握手”觉得很有意思。贴主提出“TCP建立连接为什么是三次握手?”的问题,在众多回复中,有一条回复写道:“这个问题的本质是, 信道不可靠, 但是通信双发需要就某个问题达成一致. 而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足"在不可靠信道上可靠地传输信息"这一需求所导致的. 请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了. 因此,如果信道是可靠的, 即无论什么时候发出消息, 对方一定能收到, 或者你不关心是否要保证对方收到你的消息, 那就能像UDP那样直接发送消息就可以了.”。
四次分手:
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
状态详解:
CLOSED: 这个没什么好说的了,表示初始状态。
LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
ESTABLISHED:这个容易理解了,表示连接已经建立了。
FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
二、Understanding TCP Sequence and Acknowledgment Numbers
http://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/
http://blog.csdn.net/a19881029/article/details/38091243
通常我们使用netstat命令监视网络状态,最常用的就是netstat -an命令!在State下面有一些状态说明信息,简单说一下这些英文具体都代表什么:
LISTEN:(Listening for a connection.)
侦听来自远方的TCP端口的连接请求。
SYN-SENT:(Active; sent SYN. Waiting for a matching connection request after having sent a connection
request.)
在发送连接请求后等待匹配的连接请求
SYN-RECEIVED:(Sent and received SYN. Waiting for a confirming connection request acknowledgment
after having both received and sent connection requests.)
在收到和发送一个连接请求后等待对方对连接请求的确认
ESTABLISHED:(Connection established.)
代表一个已建立的连接
FIN-WAIT-1:(Closed; sent FIN.)
等待远程TCP连接中断请求,或先前的连接中断请求的确认
FIN-WAIT-2:(Closed; FIN is acknowledged; awaiting FIN.)
从远程TCP等待连接中断请求
CLOSE-WAIT:(Received FIN; waiting to receive CLOSE.)
等待从本地用户发来的连接中断请求
CLOSING:(Closed; exchanged FIN; waiting for FIN.)
等待远程TCP对连接中断的确认
LAST-ACK:(Received FIN and CLOSE; waiting for FIN ACK.)
等待原来的发向远程TCP的连接中断请求的确认
TIME-WAIT:(In 2 MSL (twice the maximum segment length) quiet wait after close. )
等待足够的时间以确保远程TCP接收到连接中断请求的确认
CLOSED:(Connection is closed.)
没有任何连接状态
首先要说明的是要明确TCP连接建立的过程需要3次握手,下面举例说明各种状态存在的时刻:
1. 首先在服务器A上开启FTP服务,开始侦听来自远端TCP端口的连接请求,这个时候查看服务器A状态为:LISTENING
2. 在客户端B上向A发送FTP连接请求,这个时候数据包同步SYN位设置为1,这是TCP三次握手的第一步。在发送后没收到确认时,在客户端B上其状态为:SYN-SENT。此时客户端B启动连接定时器。如果在75秒内没有收到应答,则放弃连接建立。
3. 在服务器A上收到从B上发送的SYN同步包后,确认,然后再向B发送SYN的同步包,此数据包同时将TCP标记中的同步位和确认位设置1,它既对第一步中的客户端同步数据包进行确认,表示愿意与客户端同步,同时再对客户端主机进行同步请求,这是TCP连接的第一步。这个时候在服务器A上,状态为:SYN-RECEIVED。此时服务器A启动连接定时器。如果在75秒内没有收到应答,则放弃连接建立。
4. 在客户端B上接收到从A上发过来的确认同步包后进行确认,此数据包中将TCP标记中的确认位置1,表示这是一个确认数据包,此时在客户端B状态转换为:ESTABLISHED
5. 服务器A接收到从B发过来的确认包后,状态转换为:ESTABLISHED
此时TCP连接正式建立。
1. 应用程序在在连接不需要的时候,通过客户端B向服务器A发送的终止信息的FIN包后,客户端B处于FIN-WAIT-1状态。
2. 服务器A接收到客户端B发送的终止数据包,它告诉客户端B已成功接收客户端的数据包,此时等待应用程序来关闭连接,此时服务器A进入CLOSE_WAIT状态。
3. 客户端B接收到带有确认位的数据包后,对此进行确认,同意关闭TCP连接此时客户端B转移到FIN-WAIT-2状态。当连接从FIN-WAIT-1状态转移到FIN-WAIT-2状态时,将一个FIN-WAIT-2定时器设置为10分钟。
4. 服务器A在应用程序同意终止连接后,向客户端B发送终止FIN包,此时服务器状态转为LAST-ACT。
5. 客户端B在接收到从服务器A发送的终止包后,同意终止连接,然后再向服务器端发送确认信息,此时客户端B转向TIME-WAIT状态。当连接进入TIME-WAIT状态时,该定时器被激活。
6. 服务端A在收到客户端B的确认后,关闭连接,服务器A状态转向CLOSED。
7. 客户端B在TIME-WAIT定时器超时时,与该连接相关的内核数据块被删除,连接终止,转向CLOSED状态。
此时TCP连接正式关闭。
连接终止请求对与建立连接的双方是可以同时发出的,在发出终止请求后,双方都进入FIN-WAIT-1状态,随着定时器的超时,双方都进入CLOSING状态,在这个定时器再次超时后,均转入TIME-WAIT状态,在TIME-WAIT的定时器超时后,双方均放弃这次连接,连接转为CLOSE状态。如图示: