本文共 5449 字,大约阅读时间需要 18 分钟。
TCP协议提供可靠的面向连接服务,采用三次握手建立连接。
第一次握手:建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;第二次握手:服务器收到SYN包,向客户端返回ACK(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RCVD状态;第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。完成三次握手,客户端与服务器开始传送数据,也就是ESTABLISHED状态。
#
采用四次挥手断开双向连接。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。(3) 服务器关闭客户端的连接,发送一个FIN给客户端。(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
**三次握手**是`TCP/IP`建立连接的确认机制,是客户端和服务器双方要确认对方能收到自己的信息,而**三次握手**是最短路径。1. 第一次握手:建立连接时,`Client`发送请求报文段(`syn seq=x`),进入`SYN_SENT`状态,等待`Server`确认。2. 第二次握手:服务器收到,`Server`回复信息给`Client`,包含给客户端的确认信息,和服务器自身的报文信息(`ack=x+1 syn seq=y`),此时服务器进入`SYN_RECV`状态。3. 第三次握手:客户端收到`SYN+ACK`包,`Client`回复服务器(`ack=y+1`),客户端和服务器进入`ESTABLISHED`(TCP连接成功)状态,完成三次握手。三次握手完成后,客户端与服务器开始传送数据。
形象比喻
- A 向 B 发起建立连接请求:A——>B;
- B 收到 A 的发送信号,并且向A发送确认信息:B——>A;
- A 收到 B 的确认信号,并向B发送确认信号:A——>B。
通过第一次握手,B 知道 A 能够发送数据。通过第二次握手,A 知道 B 能发送数据。
结合第一次握手和第二次握手,A 知道 B 能接收数据。结合第三次握手,B知道A能够接收数据。至此,完成了握手过程,A 知道 B 能收能发,B 知道 A 能收能发,通信连接至此建立。
三次连接是保证可靠的最小握手次数,再多次握手也不能提高通信成功的概率,反而浪费资源。
**四次挥手**是`TCP/IP`关闭连接的确认机制。对于一个已经建立的连接,TCP使用改进的三次握手来释放连接(使用一个带有FIN附加标记的报文段)。TCP关闭连接的步骤如下:1. 第一步:当主机 **A** 的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有`FIN`附加标记的报文段(FIN表示英文finish)。2. 第二步:主机 **B** 收到这个`FIN`报文段之后,并不立即用**FIN**报文段回复主机A,而是先向主机A发送一个确认序号**ACK**,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。3. 第三步:主机 **B** 的应用程序告诉**TCP**:我要彻底的关闭连接,**TCP**向主机 **A**送一个`FIN`报文段。4. 第四步:主机 **A** 收到这个 `FIN` 报文段后,向主机 **B** 发送一个`ACK`表示连接彻底释放。
形象比喻
- A 向 B 发起请求(fin),表示A没有数据要发送了:A——>B;
- B 向 A 发送信号(ack),知道A要请求断开;
- B 向 A 发送信号(fin),数据接收完成,告知B要关闭连接:B——>A;
- A 向 B 收到信号(fin)向B发送(ack),确认断开:A——>B。
- B 收到确认信号,断开连接,而A在一段时间内没收到B的信号,表明B已经断开了,于是A也断开了连接。至此,完成挥手过程。
2,3次挥手不能合为一次,因为此时 A 虽然不再发送数据了,但是还可以接收数据,B可能还有数据要发送给A,所以两次挥手不能合并为一次。
挥手次数比握手多一次,是因为握手过程,通信只需要处理连接。而挥手过程,通信需要处理数据+连接。
(1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。
(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。(3) 客户必须再次回应服务段一个ACK报文,这是报文段3。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号(3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)(4) 客户段发回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报文
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
CLOSED->LISTEN->SYN收到 ->ESTABLISHED->CLOSE_WAIT->LAST->ACK->CLOSED
TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。处理原则:当TCP执行一个主动关闭,并发回最后一个ACK,该链接必须在TIME_WAIT状态停留的时间为2MSL。这样可让TCP有机会在此发送最后一个ACK以防这个ACK丢失(在另一端发送FIN前提)
但是,在连接处于2MSL等待时,任何迟到返回的报文段将被丢弃。因为处于2MSL等待的、由该插口对(socket pair)定义的连接在这段时间内不能被再用,对于客户程序还好 一些,但是对于服务程序,例如httpd,它总是要使用同一个端口80来进行服务,而在 2MSL时间内,启动httpd就会出现错误(插口被使用)。为了避免这个错误,服务器给出了一个平静时间(quit time)的概念,这是说在2MSL时间内,虽然可以重新启动服务器,但是这个服务器还是要平静等待MSL时间才能进行下一次连接,让后来返回的数据包没有机会影响到发送端,因为返回的包和重新建立的包使用同一个四元组,发送端无法区分这两个包属于不同连接。(建议MSL时间为2min,不过这个与操作系统有关。)
如果以防已经关闭或异常终止连接而另一方却不知道,我们将这样的TCP连接称为半打开的。这种状态可以通过Keepalive选项来进行发现两一段已经消失。还有一种形式是:本端发送SYN,对端回应ACK+SYN,此时本段不回应ACK。
**当处于半打开状态的一方重启并重新连接后,它将丢失复位前的所有信息,因此它并不知道数据报文段中提到的连接。此时就会返回RST(异常终止要发送RST置位的包)包应答,已关闭此次连接。此时只需要等待MSL时间,因为TCP默认机器重启的时间大于MSL。PIX防火墙和IDS*检测系统都可以伪装×××目标发送RST的包去终止异常的TCP连接。(比如限定连接的时间,减少半开连接限制超时时间)当我们Telnet一个不存在的端口号时,本段立马收到一个拒绝访问的包,这个就是对方发送的RST包导致的。
单方向链路关闭。即TCP连接一端在结束它的发送后还能接收来自另一端数据的能力。程序调用的是shutdown,而不是close,不过大多数程序都是调用close终止两个方向的连接。
最大报文段长度表示TCP传往另一端的最大块数据的长度。当建立一个连接时,每一方都受到对方通告的MSS值(MSS选项只能出现在SYN报文中)。如果一方收不到另一方的MSS值,那么就设为默认的536字节。MSS是最长见的选项字段,还有另一个选项叫做窗口放大因子(Window*Shift Count即可以发送超大的数据包,即乘以目前窗口的倍数为实际一次发送的数据量。解决高速链路和高速主机普通TCP发包过慢问题。)。还有一些HASH值也会放在Option字段。而防火墙默认则会清掉IP和TCP的Option选项字段。
转载于:https://blog.51cto.com/13854765/2163386