网络知识
001. 能不能说一说 TCP 和 UDP 的区别?
首先概括一下基本的区别:
- TCP是一个面向连接的、可靠的、基于字节流的传输层协议。
- 而UDP是一个面向无连接的传输层协议。(就这么简单,其它TCP的特性也就没有了)。
具体来分析,和 UDP 相比,TCP 有三大核心特性:
-
面向连接
。所谓的连接,指的是客户端和服务器的连接,在双方互相通信之前,TCP 需要三次握手建立连接,而 UDP 没有相应建立连接的过程。 -
可靠性
。TCP 花了非常多的功夫保证连接的可靠,这个可靠性体现在哪些方面呢?一个是有状态,另一个是可控制。
TCP 会精准记录哪些数据发送了,哪些数据被对方接收了,哪些没有被接收到,而且保证数据包按序到达,不允许半点差错。这是有状态。
当意识到丢包了或者网络环境不佳,TCP 会根据具体情况调整自己的行为,控制自己的发送速度或者重发。这是可控制。
相应的,UDP 就是无状态, 不可控的。 -
面向字节流
。UDP 的数据传输是基于数据报的,这是因为仅仅只是继承了 IP 层的特性,而 TCP 为了维护状态,将一个个 IP 包变成了字节流。
002: 说说 TCP 三次握手的过程?为什么是三次而不是两次、四次?
对应到 TCP 的三次握手,也是需要确认双方的两样能力: 发送的能力和接收的能力
。于是便会有下面的三次握手的过程:
CLOSED
:client 处于关闭状态
LISTEN
:server 处于监听状态,等待 client 连接
SYN -RCVDRCVD
:表示 server 接受到了 SYN 报文,当收到 client 的ACK 报文后,它会进入到 ESTABLISHED 状态
SYN -SENT
:表示 client 已发送 SYN 报文,等待 server 的第 2次握手
ESTABLISHED
:表示连接已经建立
从最开始双方都处于CLOSED状态
。然后服务端开始监听某个端口,进入了LISTEN状态
。
然后客户端主动发起连接,发送 SYN , 自己变成了SYN-SENT状态
。
服务端接收到,返回SYN和ACK(对应客户端发来的SYN)
,自己变成了SYN-REVD
。
之后客户端再发送ACK给服务端,自己变成了ESTABLISHED状态
;服务端收到ACK之后,也变成了ESTABLISHED状态
。
为什么不是两次?
主要目的:防止 server 端一直等待,浪费资源
如果建立连接只需要 2次握手,可能会出现的情况
假设 client 发出的第一个连接请求报文段,因为网络延迟在释放以后某时间才到达 server
本来这是一个早已失效的连接请求,但 server 收到此失效的请求后,误认为是 client 再次发出的一个新连接请求
于是 server 就向 client 发出确认报文段
,同意建立连接
如果不采用“ 3次握手”,那么只要 server 发出确认,新的连接就建立
了
由于现在 client 并没有真正想连接服务器的意愿,因此不会理睬 server 的确认
,也不会向 server 发送数据
但server 却以为新的连接已经建立,并一直等待 client 发来数据
, 这样server 的很多资源就白浪费掉了
采用“三次握手”的办法可以防止上述现象发生
例如上述情况, client 没有向 server 的确认发出, server 由于收不到确认
,就知道 client 并没有要求建立连接
为什么不是四次?
三次握手的目的是确认双方发送和接收的能力,那四次握手可以嘛?
当然可以,100 次都可以。但为了解决问题,三次就足够了,再多用处就不大了。
第3次握手失败了,会怎么处理?
此时 server 的状态为 SYN -RCVDRCVD
,若等不到 client 的ACK
,server 会重新发送 SYN+ACK 包
如果 server 多次重发 SYN+ACK 都等不到
client 的ACK,就会发送 RST 包
,强制关闭连接
三次握手过程中可以携带数据么?
第三次握手的时候,可以携带
。前两次握手不能携带
数据。
如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文中放大量数据
,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。
第三次握手的时候,客户端已经处于ESTABLISHED状态
,并且已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。
同时打开会怎样?
如果双方同时发 SYN报文,状态变化会是怎样的呢?
这是一个可能会发生的情况。
状态变迁如下:
在发送方给接收方发SYN
报文的同时,接收方也给发送方发SYN
报文,两个人刚上了!
发完SYN,两者的状态都变为SYN-SENT
。
在各自收到对方的SYN后
,两者状态都变为SYN-REVD
。
接着会回复对应的ACK + SYN
,这个报文在对方接收之后,两者状态一起变为ESTABLISHED
。
这就是同时打开情况下的状态变迁。
003: 说说 TCP 四次挥手的过程
过程拆解
FIN -WAITWAIT-1
:表示想主动关闭连接
向对方发送了 FIN 报文,此时进入到 FIN -WAITWAIT-1状态
CLOSECLOSE-WAITWAIT
:表示在等待关闭
当对方发送 FIN 给自己,会回应一个 ACK 报文给对方,此时则进入到 CLOSECLOSE-WAIT 状态
在此状态下,需要考虑自己是否还有数据发送 给对方如果没FIN 报文给对方
FIN -WAITWAIT-2
:只要对方发送 ACK 确认后,主动方就会处于 FIN -WAITWAIT-2状态,然后等待对方发送 FIN 报文
CLOSING
:一种比较罕见的例外状态
表示你发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却也收到了对方的 FIN 报文
如果双方几乎在同时准备关闭连接的话,那么就出现了发送 FIN 报文的情况,也即会出现 CLOSING 状态
表示双方都正在关闭连接
LAST-ACK
:被动关闭一方在发送 FIN 报文后,最等待对方的 ACK 报文
当收到 ACK 报文后,即可进入 CLOSED 状态了
TIME -WAITWAIT
:表示收到了对方的 FIN 报文,并发送出了 ACK 报文,就等 2MSL 后即可进入 CLOSED 状态了
如果 FIN -WAITWAIT-1状态下,收到了对方同时带 FIN 标志和 ACK 标志的报文时
可以直接进入到 TIME -WAIT 状态,而无须经过 FIN -WAITWAIT-2状态
CLOSED
:关闭状态
刚开始双方处于ESTABLISHED
状态。
客户端要断开了,向服务器发送 FIN
报文,在 TCP 报文中的位置如下图:
发送后客户端变成了FIN-WAIT-1
状态。注意, 这时候客户端同时也变成了half-close(半关闭)状态
,即无法向服务端发送报文,只能接收
。
服务端接收后向客户端确认,变成了CLOSED-WAIT
状态。
客户端接收到了服务端的确认,变成了FIN-WAIT2
状态。
随后,服务端向客户端发送FIN
,自己进入LAST-ACK
状态,
客户端收到服务端发来的FIN
后,自己变成了TIME-WAIT
状态,然后发送 ACK
给服务端。
注意了,这个时候,客户端需要等待足够长的时间,具体来说,是 2 个 MSL(Maximum Segment Lifetime,报文最大生存时间), 在这段时间内如果客户端没有收到服务端的重发请求,那么表示 ACK 成功到达,挥手结束,否则客户端重发 ACK。
等待2MSL的意义
如果不等待会怎样?
可以防止本次连接中产生的数据包误传到下一次连接中(因为都会在 2MSL 时间内消失了)
如果 client 发送 ACK 后马上释放了, 然又因为网络原server 没有收到 client 的ACK,server 就会重发 FIN
这时可能出现的情况是
① client 没有任何响应,服务器那边会干等甚至多次重发 FIN ,浪费资源
② client 有个新的应用程序刚好分配了同一端口号,收到 FIN 后马上开始执行断连接的操作,本来 它可能是想跟 server 建立连接的
一个 MSL 不就不够了吗,为什么要等待 2 MSL?
● 1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端
● 1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达
这就是等待 2MSL 的意义。
为什么是四次挥手而不是三次?
因为服务端在接收到FIN, 往往不会立即返回FIN, 必须等到服务端所有的报文都发送完毕了
,才能发FIN。因此先发一个ACK表示已经收到客户端的FIN
,延迟一段时间才发FIN。这就造成了四次挥手。
如果是三次挥手会有什么问题?
等于说服务端将ACK和FIN的发送合并为一次挥手,这个时候长时间的延迟可能会导致客户端误以为FIN没有到达客户端
,从而让客户端不