网络协议常见问题
DNS 域名解析过程
DNS 客户端进行域名 www.tsinghua.edu.cn 的解析过程如下:
- DNS 客户端向本地域名服务器发送请求,查询 www.tsinghua.edu.cn 主机的 IP 地址;
- 本地域名服务器查询数据库,发现没有域名为 www.tsinghua.edu.cn 的主机,于是将请求发送给根域名服务器;
- 根域名服务器查询数据库,发现没有这个主机域名记录,但是根域名服务器知道 cn 域名服务器可以解析这个域名,于是将 cn 域名服务器的 IP 地址返回给本地域名服务器;
- 本地域名服务器向 cn 域名服务器查询 www.tsinghua.edu.cn 主机的 IP 地址;
- cn 域名服务器查询数据库,也没有相关记录,但是知道 edu.cn 域名服务器可以解析这个域名,于是将 edu.cn 域名服务器的 IP 地址返回给本地域名服务器;
- 本地域名服务器再向 edu.cn 域名服务器查询 www.tsinghua.edu.cn 主机 IP 地址;
- edu.cn 域名服务器查询数据库,也没有相关记录,但是知道 tsinghua.edu.cn 域名服务器可以解析这个域名,于是将 tsinghua.edu.cn 的域名服务器 IP 地址返回给本地域名服务器;
- 本地域名服务器向 tsinghua.edu.cn 域名服务器查询 www.tsinghua.edu.cn 主机的 IP 地址;
- tsinghua.edu.cn 域名服务器查询数据库,发现有主机域名记录,于是给本地域名服务器返回 www.tsinghua.edu.cn 对应的 IP 地址;
- 最后本地域名服务器将 www.tsinghua.edu.cn 的 IP 地址返回给客户端,整个解析过程完成。
TCP建立连接三次握手
三次握手的过程,需要说明状态转换
- 第一次握手:客户端发送
SYN
报文,并进入SYN_SENT
状态,等待服务器的确认; - 第二次握手:服务器收到
SYN
报文,需要给客户端发送ACK
确认报文,同时服务器也要向客户端发送一个SYN
报文,所以也就是向客户端发送SYN + ACK
报文,此时服务器进入SYN_RCVD
状态; - 第三次握手:客户端收到
SYN + ACK
报文,向服务器发送确认包,客户端进入ESTABLISHED
状态。待服务器收到客户端发送的ACK
包也会进入ESTABLISHED
状态,完成三次握手。
为什么要三次握手,两次是否可以
- (一)确认双方的收发能力
TCP 建立连接之前,需要确认客户端与服务器双方的收包和发包的能力。
1. 第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
2. 第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
3. 第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
所以,只有三次握手才能确认双方的接收与发送能力是否正常。
- (二)序列号可靠同步
如果是两次握手,服务端无法确定客户端是否已经接收到了自己发送的初始序列号,如果第二次握手报文丢失,那么客户端就无法知道服务端的初始序列号,那 TCP 的可靠性就无从谈起。
- (三)阻止重复历史连接的初始化
客户端由于某种原因发送了两个不同序号的
SYN
包,我们知道网络环境是复杂的,旧的数据包有可能先到达服务器。如果是两次握手,服务器收到旧的SYN
就会立刻建立连接,那么会造成网络异常。如果是三次握手,服务器需要回复
SYN+ACK
包,客户端会对比应答的序号,如果发现是旧的报文,就会给服务器发RST
报文,直到正常的SYN
到达服务器后才正常建立连接。所以三次握手才有足够的上下文信息来判断当前连接是否是历史连接。
- (四)安全问题
我们知道 TCP 新建连接时,内核会为连接分配一系列的内存资源,如果采用两次握手,就建立连接,那会放大 DDOS 攻击的。
TCP 作为一种可靠传输控制协议,其核心思想:既要保证数据可靠传输,又要提高传输的效率,而三次握手恰好可以满足以上两方面的需求!
初始序列号(ISN)
ISN 是什么?
答:ISN
全称是 Initial Sequence Number
,是 TCP 发送方的字节数据编号的原点,告诉对方我要开始发送数据的初始化序列号
ISN 是固定不变的吗?
答:ISN 如果是固定的,攻击者很容易猜出后续的确认序号,为了安全起见,避免被第三方猜到从而发送伪造的 RST
报文,因此 ISN 是动态生成的连接队列
半连接队列?
什么是半连接队列?
答:服务器第一次收到客户端的 SYN
之后,就会处于 SYN_RCVD
状态,此时双方还没有完全建立连接。服务器会把这种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
三次握手可以携带数据吗?
第一次、第二次握手不可以携带数据,而第三次握手是可以携带数据的。
我们可以思考一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据,疯狂着重复发 SYN 报文,这会让服务器花费大量的内存空间来缓存这些报文,这样服务器就更容易被攻击了。
对于第三次握手,此时客户端已经处于连接状态,他已经知道服务器的接收、发送能力是正常的了,所以可以携带数据是情理之中。
TCP 断开连接四次挥手
四次挥手的过程,需要说明状态转换
- 第一次挥手。客户端发起
FIN
包(FIN = 1),客户端进入FIN_WAIT_1
状态。TCP 规定,即使FIN
包不携带数据,也要消耗一个序号。 - 第二次挥手。服务器端收到
FIN
包,发出确认包ACK
(ack = u + 1),并带上自己的序号 seq=v,服务器端进入了CLOSE_WAIT
状态。这个时候客户端已经没有数据要发送了,不过服务器端有数据发送的话,客户端依然需要接收。客户端接收到服务器端发送的ACK
后,进入了FIN_WAIT_2
状态。 - 第三次挥手。服务器端数据发送完毕后,向客户端发送
FIN
包(seq=w ack=u+1),半连接状态下服务器可能又发送了一些数据,假设发送 seq 为 w。服务器此时进入了LAST_ACK
状态。 - 第四次挥手。客户端收到服务器的
FIN
包后,发出确认包(ACK=1,ack=w+1),此时客户端就进入了TIME_WAIT
状态。注意此时 TCP 连接还没有释放,必须经过2*MSL
后,才进入CLOSED
状态。而服务器端收到客户端的确认包ACK
后就进入了CLOSED
状态,可以看出服务器端结束 TCP 连接的时间要比客户端早一些。
为什么建立连接握手三次,关闭连接时需要是四次呢?
其实在 TCP 握手的时候,接收端发送 SYN+ACK
的包是将一个 ACK
和一个 SYN
合并到一个包中,所以减少了一次包的发送,三次完成握手。
对于四次挥手,因为 TCP 是全双工通信,在主动关闭方发送 FIN 包后,接收端可能还要发送数据,不能立即关闭服务器端到客户端的数据通道,所以也就不能将服务器端的 FIN
包与对客户端的 ACK
包合并发送,只能先确认 ACK
,然后服务器待无需发送数据时再发送 FIN
包,所以四次挥手时必须是四次数据包的交互。
为什么TIME_WAIT 状态需要经过 2MSL 才能返回到 CLOSE 状态?
MSL
指的是报文在网络中最大生存时间。在客户端发送对服务器端的 FIN
的确认包 ACK
后,这个 ACK
包是有可能不可达的,服务器端如果收不到 ACK
的话需要重新发送 FIN
包。
所以客户端发送 ACK
后需要留出 2MSL
时间(ACK 到达服务器 + 服务器发送 FIN 重传包,一来一回)等待确认服务器端确实收到了 ACK 包。
也就是说客户端如果等待 2MSL
时间也没有收到服务器端的重传包 FIN
,说明可以确认服务器已经收到客户端发送的 ACK
。
还有第 2 个理由,避免新旧连接混淆。
在客户端发送完最后一个 ACK
报文段后,在经过 2MSL
时间,就可以使本连接持续的时间内所产生的所有报文都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文。
你要知道,有些自作主张的路由器会缓存 IP 数据包,如果连接重用了,那么这些延迟收到的包就有可能会跟新连接混在一起。