室友在今天再次经历了字节跳动的面试,面试我全程助攻,对于面试过程以及面试官的态度和问题也都有听到,当面试官再次问道tcp的握手过程时,我不禁感叹这个东西我要是不会是真不行啊!所以背着室友在这里总结他的面试经历。
面试官是由TCP和UDP区别开始问起的, 然后问到TCP的三次握手过程:
这里首先讲解什么是三次握手?
三次握手就是在客户端和服务端进行TCP连接时需要发送三个包,目的是确定客户端和服务端的发送能力和接收能力都没有问题、实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小
信息。
三次握手的过程:
第一次握手:客户端向服务端发送SYN报文段,并指明客户端的初始化序列号 ISN。
第二次握手:服务端收到客户端发送的SYN报文段,向客户端发送SYN报文,同时确定自己的ISN初始化序列号。
第三次握手:客户端向服务端发送ACK报文来建立TCP连接。
握手为什么要三次,两次行不行?
三次握手主要是为了确定客户端以及服务端的接收能力和发送能力都没问题
第一次握手:客户端发送报文,服务端接收报文,确认了客户端的发送能力以及服务端的接收能力都没问题;
第二次握手:服务端发送报文,客户端接收报文,客户端确认了自己的发送能力和接收能力和服务端的接收能力以及发送能力没问题,但是服务端没法确认客户端的接收能力是否正常。
第三次握手:服务端接收到客户端发送的确认报文,服务端确认了客户端的发送和接收能力都没问题
这个时候面试官问了如果第三次握手时问到了ACK报文重传机制:
ACK报文重传机制:
当发送端向接收端发送SYN报文时,接收端接收SYN报文并向发送端发送SYN-ACK确认报文。当接收端等待服务端发送的确认报文时,确认报文丢失,导致等待超时,接收端就会重新发送SYN报文。且等待时间是不同的成指数形式增长。
面试官又问了SYN攻击(这个东西室友不会,全称是我引导着去说的)
SYN攻击:
说到SYN攻击就不得不说tcp连接的资源分配,服务端的资源分配是在第二次握手,客户端是在第三次握手时进行的资源分配,
既然第三次握手时服务端已经给客户端分配好了资源,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,
并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
SYN 攻击是一种典型的 DoS/DDoS 攻击。
不停的占用服务端的资源直至服务端资源被占满
接着是我觉得这里应该有的半连接状态的定义
半连接状态:
当第二次握手进行之后服务端就处于一个半连接状态,也就是只要接收到客户端的SYN-ACK报文就可以完成连接;
这次面试官还真么问四次挥手但是我觉得四次挥手也比较重要,我还时把他总结出来以备不时之需
什么是四次挥手
建立连接时需要三次握手,断开连接时需要四次挥手,这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号
第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号
第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,,此时客户端处于 TIME_WAIT
状态,需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED
状态。
在TIME-WAIT状态下等待的时间:2MSL(字段的最大存存活时间是MSL,也就是报文在tcp连接中存活的最大时间)
挥手为什么是四次?
客户端向服务端发送FIN报文,客户端告诉服务端“我已经没有文件要发了,我要关闭这个连接了”,服务段接收后,服务端还有很多文件没有发送完,所以无法立即关闭这个连接,所以先向客户端发送一个ACk报文告诉客户端“我知道了,等我发送完吧”,当服务端发送完时向客户端发送一个FIN报文告诉客户端“我已经没有文件要发送了,我也要关闭这个连接了”,客户端接收这个报文并向服务端发送ACK报文告诉服务端“我收到了”,此时客户端就处于TIME-WIAT状态等待2MSL时间。
2MSL的意义?
确定ACK报文到达:如果ACK报文丢失,服务端接收超时,重新发送FIN报文,客户端需要保证在服务端没有接收到ACK报文时,还能接收到服务端重发的FIN报文。
避免下次连接时发送上一次的报文:如果客户端发送完ACK报文,这个ACK报文由于网络原因在某个地方搁浅了,服务端超时重发FIN报文,然后重新发送ACK报文并且服务端接收后连接关闭。然后重新发送tcp连接请求,上一次没发送过去的ACK报文已经死亡,所以避免了再次传输过去上一次的报文。