概述
我们都知道 TCP 是 可靠的数据传输协议, UDP 是不可靠传输, 那么 TCP 它是怎么保证可靠传输的呢? 那我们就不得不提 TCP 的三次握手和四次挥手.
三次握手
下图为三次握手的流程图
下面通过我们 wireshark 抓包工具来分析三次握手
三次握手数据包
第一次握手
建立连接. 客户端发送连接请求报文段, 将 SYN 位置为 1,Sequence Number 为 x;(x 是随机生成的一个 int 数值)然后, 客户端进入 SYN_SEND 状态, 等待服务器的确认;
第二次握手
服务器收到 SYN 报文段. 服务器收到客户端的 SYN 报文段, 需要对这个 SYN 报文段进行确认, 设置 Acknowledgment Number 为 x+1(Sequence Number+1); 同时, 自己自己还要发送 SYN 请求信息, 将 SYN 位置为 1,Sequence Number 为 y (y 是随机生存的一个 int 数值); 服务器端将上述所有信息放到一个报文段 (即 SYN+ACK 报文段) 中, 一并发送给客户端, 此时服务器进入 SYN_RECV 状态;
第三次握手
客户端收到服务器的 SYN+ACK 报文段. 然后将 Acknowledgment Number 设置为 y+1, 向服务器发送 ACK 报文段, 这个报文段发送完毕以后, 客户端和服务器端都进入 ESTABLISHED 状态, 完成 TCP 三次握手.
四次挥手
第一次挥手:
Client (可以使客户端, 也可以是服务器端), 设置 Sequence Number 和 Acknowledgment Number, 向 Server 发送一个 FIN 报文段; 此时, Client 进入 FIN_WAIT_1 状态; 这表示 Client 没有数据要发送给 Server 了;
客户端发送第一次挥手后, 就不能在向 服务端发送数据了.
第二次挥手:
Server 收到了 Client 发送的 FIN 报文段, 向 Client 回一个 ACK 报文段, Acknowledgment Number 为 Sequence Number 加 1;Client 进入 FIN_WAIT_2 状态; Server 告诉 Client , 我 "同意" 你的关闭请求;
Server 第一次响应后, 还可以继续向 Client 发送数据, 这里只是告诉 Client , 我收到你发送的关闭请求.
第三次挥手
Server 向 Client 发送 FIN 报文段, 请求关闭连接, 同时 Server 进入 CLOSE_WAIT 状态;
当 Server 的数据响应完成后, 再告诉 Client, 我这边也可以关闭请求了, 这时
Server 就不能再向 Client 发送数据了
第四次挥手
Client 收到 Server 发送的 FIN 报文段, 向 Server 发送 ACK 报文段, 然后 Client 进入
TIME_WAIT 状态; Server 收到 Client 的 ACK 报文段以后, 就关闭连接; 此时, Client
等待 2MSL 后依然没有收到回复, 则证明 Server 端已正常关闭, 那好, Client 也可以关闭连接了.
什么是 MSL
MSL 是 Maximum Segment Lifetime 英文的缩写, 中文可以译为 "报文最大生存时间", 他是任何报文在网络上存在的最长时间, 超过这个时间报文将被丢弃. 因为 tcp 报文 (segment) 是 ip 数据报 (datagram) 的数据部分, 具体称谓请参见《数据在网络各层中的称呼》一文, 而 ip 头中有一个 TTL 域, TTL 是 time to live 的缩写, 中文可以译为 "生存时间", 这个生存时间是由源主机设置初始值但不是存的具体时间, 而是存储了一个 ip 数据报可以经过的最大路由数, 每经过一个处理他的路由器此值就减 1, 当此值为 0 则数据报将被丢弃, 同时发送 ICMP 报文通知源主机. RFC 793 中规定 MSL 为 2 分钟, 实际应用中常用的是 30 秒, 1 分钟和 2 分钟等.
2MSL 即两倍的 MSL,TCP 的 TIME_WAIT 状态也称为 2MSL 等待状态, 当 TCP 的一端发起主动关闭, 在发出最后一个 ACK 包后, 即第 3 次握手完成后发送了第四次握手的 ACK 包后就进入了 TIME_WAIT 状态, 必须在此状态上停留两倍的 MSL 时间, 等待 2MSL 时间主要目的是怕最后一个 ACK 包对方没收到, 那么对方在超时后将重发第三次握手的 FIN 包, 主动关闭端接到重发的 FIN 包后可以再发一个 ACK 应答包. 在 TIME_WAIT 状态时两端的端口不能使用, 要等到 2MSL 时间结束才可继续使用. 当连接处于 2MSL 等待阶段时任何迟到的报文段都将被丢弃. 不过在实际应用中可以通过设置 SO_REUSEADDR 选项达到不必等待 2MSL 时间结束再使用此端口.
TTL 与 MSL 是有关系的但不是简单的相等的关系, MSL 要大于等于 TTL.
为什么要三次握手?
为什么要三次握手
TCP 建立连接, 其实通过两次握手就可以建立连接了, 为什么要三次呢? 是不是多此一举呢?
1,《计算机网络》中是这样说的:
为了防止已失效的连接请求报文段突然又传送到了服务端, 因而产生错误.
在书中同时举了一个例子, 如下:
已失效的连接请求报文段 "的产生在这样一种情况下: client 发出的第一个连接请求报文段并没有丢失, 而是在某个网络结点长时间的滞留了, 以致延误到连接释放以后的某个时间才到达 server. 本来这是一个早已失效的报文段. 但 server 收到此失效的连接请求报文段后, 就误认为是 client 再次发出的一个新的连接请求. 于是就向 client 发出确认报文段, 同意建立连接. 假设不采用" 三次握手 ", 那么只要 server 发出确认, 新的连接就建立了. 由于现在 client 并没有发出建立连接的请求, 因此不会理睬 server 的确认, 也不会向 server 发送数据. 但 server 却以为新的运输连接已经建立, 并一直等待 client 发来数据. 这样, server 的很多资源就白白浪费掉了. 采用" 三次握手 "的办法可以防止上述现象发生. 例如刚才那种情况, client 不会向 server 的确认发出确认. server 由于收不到确认, 就知道 client 并没有要求建立连接."
2, 网络故障
比如, 现在网络出现了故障, 只能发请求数据包, 而接收不到响应数据包, 那么只要发送一次请求, 服务器就建立请求, 这样肯定也是不对的, 网络请求有来有回才能完成通讯. 所以三次握手是必不可少的.
为什么要四次挥手呢
TCP 协议是一种面向连接的, 可靠的, 基于字节流的运输层通信协议. TCP 是全双工模式, 这就意味着, 当 Client 发出 FIN 报文段时, 只是表示 Client 已经没有数据要发送了, Client 告诉 Server, 它的数据已经全部发送完毕了; 但是, 这个时候 Client 还是可以接受来自 Server 的数据; 当 Server 返回 ACK 报文段时, 表示它已经知道 Client 没有数据发送了, 但是 Server 还是可以发送数据到 Client 的; 当 Server 也发送了 FIN 报文段时, 这个时候就表示 Server 也没有数据要发送了, 就会告诉 Client , 我也没有数据要发送了, 之后彼此就会愉快的中断这次 TCP 连接. 如果要正确的理解四次分手的原理, 就需要了解四次分手过程中的状态变化.
来源: http://www.bubuko.com/infodetail-2997343.html