<p>以下内容转载自 <a href="https://mp.weixin.qq.com/s/rRPvGlc0KgLECFNk_JmIxw">https://mp.weixin.qq.com/s/rRPvGlc0KgLECFNk_JmIxw</a></p>
<p>先亮出这篇文章的思维导图</p>
<p><img alt="图片" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-4aed4dd646b4a07b99dac0f46692844f.png"></p>
<p> </p>
<p>TCP 作为传输层的协议,是一个软件工程师素养的体现,也是面试中经常被问到的知识点。在此,我将 TCP 核心的一些问题梳理了一下,希望能帮到各位。</p>
<p> </p>
<p>001. 能不能说一说 TCP 和 UDP 的区别?</p>
<p> </p>
<p>首先概括一下基本的区别:</p>
<p> </p>
<p><strong>TCP是一个面向连接的、可靠的、基于字节流的传输层协议。</strong></p>
<p> </p>
<p><strong>而UDP是一个面向无连接的传输层协议。</strong>(就这么简单,其它TCP的特性也就没有了)。</p>
<p>具体来分析,和 <code>UDP</code> 相比,<code>TCP</code> 有三大核心特性:</p>
<ol><li> <p><strong>面向连接</strong>。所谓的连接,指的是客户端和服务器的连接,在双方互相通信之前,TCP 需要三次握手建立连接,而 UDP 没有相应建立连接的过程。</p> </li><li> <p><strong>可靠性</strong>。TCP 花了非常多的功夫保证连接的可靠,这个可靠性体现在哪些方面呢?一个是有状态,另一个是可控制。</p> </li></ol>
<p>TCP 会精准记录哪些数据发送了,哪些数据被对方接收了,哪些没有被接收到,而且保证数据包按序到达,不允许半点差错。这是<strong>有状态</strong>。</p>
<p> </p>
<p>当意识到丢包了或者网络环境不佳,TCP 会根据具体情况调整自己的行为,控制自己的发送速度或者重发。这是<strong>可控制</strong>。</p>
<p> </p>
<p>相应的,UDP 就是<code>无状态</code>, <code>不可控</code>的。</p>
<p> </p>
<ol><li> <p><strong>面向字节流</strong>。UDP 的数据传输是基于数据报的,这是因为仅仅只是继承了 IP 层的特性,而 TCP 为了维护状态,将一个个 IP 包变成了字节流。</p> <p> </p> </li></ol>
<p>002: 说说 TCP 三次握手的过程?为什么是三次而不是两次、四次?</p>
<p> </p>
<h3>恋爱模拟</h3>
<p> </p>
<p>以谈恋爱为例,两个人能够在一起最重要的事情是首先确认各自<strong>爱和被爱</strong>的能力。接下来我们以此来模拟三次握手的过程。</p>
<p> </p>
<p>第一次:</p>
<p>男: <strong>我爱你。</strong></p>
<p>女方收到。</p>
<p>由此证明男方拥有<code>爱</code>的能力。</p>
<p>第二次:</p>
<p>女: <strong>我收到了你的爱,我也爱你。</strong></p>
<p>男方收到。</p>
<p>OK,现在的情况说明,女方拥有<code>爱</code>和<code>被爱</code>的能力。</p>
<p>第三次:</p>
<p>男: <strong>我收到了你的爱。</strong></p>
<p>女方收到。</p>
<p>现在能够保证男方具备<code>被爱</code>的能力。</p>
<p>由此完整地确认了双方<code>爱</code>和<code>被爱</code>的能力,两人开始一段甜蜜的爱情。</p>
<p> </p>
<h3><strong>真实握手</strong></h3>
<p> </p>
<p>当然刚刚那段属于扯淡,不代表本人价值观,目的是让大家理解整个握手过程的意义,因为两个过程非常相似。对应到 TCP 的三次握手,也是需要确认双方的两样能力: <code>发送的能力</code>和<code>接收的能力</code>。于是便会有下面的三次握手的过程:</p>
<p><img alt="图片" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-70e27b82fca1d137b0aeec53a4210714.png"></p>
<p>从最开始双方都处于<code>CLOSED</code>状态。然后服务端开始监听某个端口,进入了<code>LISTEN</code>状态。</p>
<p>然后客户端主动发起连接,发送 SYN , 自己变成了<code>SYN-SENT</code>状态。</p>
<p> </p>
<p>服务端接收到,返回<code>SYN</code>和<code>ACK</code>(对应客户端发来的SYN),自己变成了<code>SYN-REVD</code>。</p>
<p> </p>
<p>之后客户端再发送<code>ACK</code>给服务端,自己变成了<code>ESTABLISHED</code>状态;服务端收到<code>ACK</code>之后,也变成了<code>ESTABLISHED</code>状态。</p>
<p> </p>
<p>另外需要提醒你注意的是,从图中可以看出,SYN 是需要消耗一个序列号的,下次发送对应的 ACK 序列号要加1,为什么呢?只需要记住一个规则:</p>
<blockquote>
<p>凡是需要对端确认的,一定消耗TCP报文的序列号。</p>
</blockquote>
<p>SYN 需要对端的确认, 而 ACK 并不需要,因此 SYN 消耗一个序列号而 ACK 不需要。</p>
<h3>为什么不是两次?</h3>
<p> </p>
<p>根本原因: 无法确认客户端的接收能力。</p>
<p> </p>
<p>分析如下:</p>
<p> </p>
<p>如果是两次,你现在发了 SYN 报文想握手,但是这个包<strong>滞留</strong>在了当前的网络中迟迟没有到达,TCP |
|