🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 1、为什么要进行三次握手?不是两次?不是四次呢? 答案一:防止已失效的连接请求又传送到服务端,因而产生资源的浪费。 答案二:为了实现可靠的数据传输,TCP协议的通信双方,都必须维护一个序列号,用来标识发送出去的数据,那些是已经被对方收到的。三次握手的过程是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤。 ### 2、为什么要进行四次挥手? 答案:TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。 ### 3、为什么 A 在 TIME-WAIT 状态必须等待 2MSL 的时间呢? > MSL:报文最大生存时间 * 为了保证A发送的最后一个ACK报文能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN报文段的ACK确认。B会超时重传这个FIN报文段,而A就能在2MSL时间内收到这个重传的FIN报文段。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后就立即释放连接,就无法收到B重传的FIN报文段,因而也不会再发送一次确认报文段。这样,B就无法按照正常的步骤进入CLOSED状态。 * A在发送完ACK报文段后,再经过2MSL时间,就可以使本连接持续的时间所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求的报文段。 ### 4、TCP是面向连接的,那么在计算机的世界里,什么是连接?怎么理解连接? 答案:连接就是通信两端即客户端和服务端各自创建一定的数据结构用来维护双方交互的状态;并不是说真的有一条类似于连接线样的管道之类的;不管是TCP还是UDP,数据最终都是经过IP层路由然后由物理层的物理媒介传输;TCP协议只不过是在传输层,做了一些判断以达到无差错不丢失不重复的按序到达。 ### 5、描述一下发送一个请求后,数据传输的流程,越详细越好。以下图中,**主机-1** 和 **主机-4** 通信为例说明。 :-: ![](https://img.kancloud.cn/27/e6/27e68918c65fcae66702a8d8709611f4_846x265.png) 1. 主机1在路由表中找到下一跳mac地址,然后将数据发送到交换机(下一跳Mac地址对应设备) 2. 交换机同样找到下一跳Mac地址,将数据报交给路由器A 3. 以此类推,最后将数据交给主机4,然后根据端口号找到对应的进程 关键点1:路由表如何寻找下一跳? :-: ![](https://img.kancloud.cn/68/b7/68b7e9de4ada13b72d8b2d0a628d8bec_654x208.png) 拿目标地址跟 Genmark 做逻辑与运算,然后再跟Destination匹配,对应的Gateway就是下一跳。 172.168.10.8 和 0.0.0.0 逻辑与运算的结果为:0.0.0.0,跟此处路由表中第一条匹配,对应的下一跳网关就是 192.168.101.254。那么此时只需要知道下一跳对应的Mac地址就可以了。 关键点2:怎么知道对应的Mac地址? :-: ![](https://img.kancloud.cn/dc/f8/dcf8cce78cef8b953c22d95bcad6f88b_582x239.png) 知道了下一跳网关,就可以在ARP缓存表中找对应的Mac地址。如果找不到,就需要用到ARP地址协议。也就是说会发出一个广播(目标MAC地址是 f:f:f:f:f:f,目的IP就是对应的下一跳网关地址) ,网段中所有主机节点都会收到这个广播包;此时,主机知道这是一个ARP广播包,然后拆开目的IP地址跟自己的不一样,就丢弃;如果一样,则回复自己的MAC地址。 ### 5、TCP三次握手期间的异常情况汇总 :-: ![](https://img.kancloud.cn/ba/f0/baf00e706eb51b9efdce8108f97ffb45_646x445.png) 1. 第一次握手丢失,会发生什么? 当客户端发出SYN报文后,就会处于SYN_SENT状态;如果客户端收不到服务端发来的SYN-ACK报文(第二次握手),就会触发超时重传机制。 至于超时的时间,不同版本的操作系统不同,有1秒的,也有3秒的,这个时间写在内核里面。那么触发超时重传后,一般要重发几次呢?一般是5次,这个由参数`tcp_syn_retries`控制,默认值一般是5。(重传策略:1秒后第一次 -》 2秒后第二次 -》 4秒后第三次 -》 8秒后第四次 -》 16秒后第5次)。 当第5次重传后,客户端继续等待32秒,如果还是收不到服务端ACK,就不在重试,直接断开连接。 所以总耗时:1+2+4+8+16+32=63秒,大约1分钟。 2. 第二次握手丢失,会发生什么? 因为第二次握手(SYN-ACK)包含两点: * 对客户端第一次SYN的确认ACK报文 * 服务端向客户端发送的SYN报文 因此,当第二次握手丢失后,客户端和服务端都会重传: * 客户端重传第一次的SYN报文,重传次数由`tcp_syn_retries`参数决定 * 服务端重传SYN-ACK报文,即第二次握手,重传次数由`tcp_synack_retries`参数决定 3. 第三次握手丢失,会发生什么? 第三次握手是对第二次握手中服务端SYN报文部分的ACK,所以当第三次握手丢失,也就意味着服务端没有收到客户端发来的ACK报文,就会触发SYN-ACK(第二次握手)的重传机制。 > ACK报文是不会有重传的,当ACK丢失了,就由对方重传对应的SYN报文。 ### 6、TCP四次挥手期间的异常情况汇总 :-: ![](https://img.kancloud.cn/8e/f4/8ef4893175a111852f010aa6d5d7166a_753x794.png) 1. 第一次挥手丢失了,会发生什么? 当客户端调用close函数关闭连接后,就会向服务端发送FIN报文,请求与服务端断开连接;那么如果这次挥手丢失了,那么客户端就会收不到服务端的ACK报文;从而就会触发超时重传机制。重传次数由`tcp_orphan_retries`参数控制。当重传次数超过设定值后,就会直接进入关闭状态。 2. 第二次挥手丢失了,会发生什么? 第二次挥手,也就是服务端收到客户端FIN报文后回传的ACK报文;由于对于ACK报文是不会重传的,所以此时依然是由客户端重传第一次挥手FIN报文,直到收到服务端的第二次挥手ACK报文或者达到最大重传 次数。 当客户端收到ACK后,就会进入到FIN_WAIT_2的状态,这个状态是在等待服务端第三次挥手FIN报文;对于close函数关闭的连接,由于无法再发送和接收数据,所以FIN_WAIT_2状态不能持续太久,由参数`tcp_fin_timeout`控制,默认值是60秒。也就意味着close关闭的连接,在60秒内还没有收到服务端的FIN报文,就会直接关闭进入close状态。 3. 第三次挥手丢失了,会发生什么? 第三次挥手,也就是服务端调用close函数,发出FIN报文,等待客户端返回ACK报文;如果长时间收不到,那么也会触发超时重传,重传次数也是由`tcp_orphan_retries`控制,与客户端重发FIN报文的控制方式一样。 4. 第四次挥手丢失了,会发生什么? 当客户端收到服务端的FIN报文后,就会回复ACK报文,此时客户端进入TIME_WAIT状态。如果服务端没有收到ACK报文,那么服务端会继续重发FIN报文。如果收到了ACK报文,就会关闭连接。但是这里的客户端会在TIME_WAIT状态持续2MSL时间后,进入close状态。