1、传输层

厨子大约 15 分钟计算机网络原创面试题传输层程序厨

1.传输层

TCP

1.0 TCP的特点

提供可靠传输,实行顺序控制或重发控制机制。具有流控制、拥塞控制、提高网络利用率等众多功能。

充分实现了数据传输时各种控制功能,可以进行丢包时的重发机制,还可以对次序乱掉的分包进行顺序控制。

TCP 的特点及其目的

TCP 通过检验和连接管理确认应答重发超时机制序列号机制以段为单位发送数据窗口控制流控制、等机制进行可靠传输。

检验和:这个原理和 MD5 完整性校验一致,目检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。

连接管理:采用三次握手的方式建立可靠的通信传输,

确认应答 : 确认应答就是会发送一条已经收到段的应答消息。

重发超时机制:这个含义在上面的序列号机制已经提到,当发送端长时间没有接收到,确认信息时,则会对该条报文进行确认,因为此时他认为,是报文发送失败。所以这个超时时间的设定就显得尤为重要。TCP采用了一个很巧妙的方法,那就是每次发包时都会,计算往返时间及其偏差,重传的时间就是比两者之和稍大一点的值。

RTT:往返时间

RTO:重发时间,重发时间略大于多次RTT的平均值

序列号机制:当发送的数据到达接收主机时,接收端主机会返回已经收到的ACK确认号,确认应答。但是确认应答有可能出现以下这种情况,报文发送时丢失,确认应答信息丢失。这样就可能会导致发送端一直重发报文。一般情况下,就发送端会等待一段时间后,如果没有收到确认应答,则会进行重发,但是我们也会遇到这种情况,当我们因为网络延迟之后,在我们发送方重传了报文之后,才接收到确认应答的信息,所以这样接收端就会收到无休止的重复包,所以这时候我们需要引入序列号机制,就是给每一个TCP报文添加一个序列号,告知发送方,我收到了哪条信息,下次传输时应该传输哪个报文。

以MSS为单位发送数据:建立TCP连接的同时,也可以确定发送数据包的单位,我们称其为最大发送长度MSS,该值是在三次握手时计算得出的,会在两者之间选择一个都可接受的最小值,TCP在发送数据时,重发时是以MSS为单位进行发送的。

流量控制,利用窗口控制提高速度:上面我们提到的,每次都要进行确认,如果往返时间较长,这会大大降低效率,所以TCP引入了窗口的概念,这样我们就可以使确认的不是每个分段,而是以最大的单位进行确认,就是发完一个段之后,不用等到确认信息,继续发段。窗口大小就是无需等待确认应答, 而可以发送数据的最大值。当然这种情况也会出现丢失段的情况,因为TCP有序列号机制,所以知道哪些段需要重发,发送方的缓冲区,会将待重发的段保存到缓冲区内,知道收到确认应答。

流控制:可以让发送端根据接收端的接收实力进行发送。接收端会向发送端发送可以接收的数据大小。另外为了防止接收不到窗口更新通知,发送端则会时不时发送一个窗口探测的数据来获取窗口信息。

拥塞控制

为了进行拥塞控制,TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。 TCP的拥塞控制采用了四种算法,即 慢开始拥塞避免快重传快恢复慢开始: 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd初始值为1,每经过一个传播轮次,cwnd加倍 2,4,8,16。指数型增长

当然慢开始的cwnd的大小不是无限制增长的,当小于 ssthresh 时,使用慢启动算法,大于等于时则启动拥塞避免算法。 拥塞避免 那么进入拥塞避免算法后,它的规则是:每当收到一个 ACK 时,cwnd 增加 1/cwnd。 此时则变成了线性增长。

当报文

就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。

当触发了重传机制,也就进入了【拥塞发生算法】

拥塞发生

此时则采用两种方法解决丢包问题

超时重传:当发生了「超时重传」,则就会使用拥塞发生算法。

这个时候,ssthresh 和 cwnd 的值会发生变化:

  • ssthresh 设为 cwnd/2

  • cwnd 重置为 1

然后就重新慢启动,这大起大落不太行。

快速重传:

还有更好的方式,前面我们讲过「快速重传算法」。当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传。

TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:

cwnd = cwnd/2 ,也就是设置为原来的一半; ssthresh = cwnd; 进入快速恢复算法

8.4 快速恢复 快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。

正如前面所说,进入快速恢复之前,cwnd 和 ssthresh 已被更新了:

cwnd = cwnd/2 ,也就是设置为原来的一半;<br />ssthresh = cwnd;

然后,进入快速恢复算法如下:

拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了); 重传丢失的数据包; 如果再收到重复的 ACK,那么 cwnd 增加 1;

如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;

拥塞控制
拥塞控制

具体细节大家可以看下这两篇文章

推荐阅读:

https://zhuanlan.zhihu.com/p/133307545open in new window

https://my.oschina.net/u/4189097/blog/4917384open in new window

1.1 TCP的粘包和拆包

TCP是面向流,没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送也有可能把多个小的包封装成一个大的数据包发送 ,这就是所谓的TCP粘包和拆包问题。

1.2 为什么会产生粘包和拆包呢?

要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包;接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包;要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包;待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MSS。解决方案:发送端将每个数据包封装为固定长度在数据尾部增加特殊字符进行分割将数据分为两部分,一部分是头部,一部分是内容体;其中头部结构大小固定,且有一个字段声明内容体的大小。

MTU:一个网络包的最大长度

MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度;

TCP头部
TCP头部

推荐阅读:https://www.cnblogs.com/yaochunhui/p/14175396.htmlopen in new window

握手

1.3三次握手是为了什么?

三次握手链接的本质是,所谓的建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。

推荐阅读:https://blog.csdn.net/qzcsu/article/details/72861891open in new window

三次握手是为了,保证可靠传输,我们假设客户端向A发送消息,首先告诉他,我要给你发消息啦,然后客户端给他发送,我收到你的消息啦,也就是Ack/syn。此条数据代表的含义为,我收到你的消息,同时我也准备好了,但是此时接受端,并不知道对方有没有收到消息,所以发送端,在收到接收端的ack和syn包之后,也要发送一个 ack 确认。这样双方则建立了链接。

三次握手过程

发送端:我发送syn(同步序列编号)的数据包给你啦。

接收端:我已经收到你的数据包啦,我将syn/ack编号发送给你啦

发送端:明白,我同时将ack的包发送给你啦。

三次握手握手情况如下

抓包情况
抓包情况

大家注意,这里三次握手时,客户端和服务端的状态也需要记忆,也是面试时的高频考点。

1.4 三次握手中,第二次握手的时候为什么还要传回SYN?

而回传SYN则是为了建立并确认从服务端到客户端的通信。是为了告诉发送端,我也准备好了。

1.5 为什么要三次握手,4次握手可以吗

  • 三次握手才可以阻止重复历史连接的初始化(主要原因)

  • 三次握手才可以同步双方的初始序列号

  • 三次握手才可以避免资源浪费

重复连接问题

因为网络会堵塞,所以有可能因为网络堵塞,第一个客户端发出第一个SYN = 10包之后,迟迟收不到SYN/ACK,所以就进行补发 SYN = 20,此时服务端收到了 SYN = 10 的旧包,然后发送ACK和SYN,但是呢?此时客户端发现我应该接收的是 SYN = 20 的ACK,而不是历史的连接,所以就会发送RST拒绝连接,等SYN= 20的 ACK来了之后,再进行连接。三次握手可以让客户端通过上下文来进行判断。

同步双方的初始序列号

序列号同步是可靠传输的基础,通过三次握手可以保证双方的序列号同步,其实四次握手也可以,只不过第二次握手把两个包合成一个了。

避免资源浪费

防止历史连接的建立,如果使用两次握手的话,现在已经连接成功,但是之前因为网络问题延迟传输的报文,再一次发到服务器则有可能再次造成连接。

TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。

不使用「两次握手」和「四次握手」的原因:

「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号; 「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

推荐阅读:https://segmentfault.com/a/1190000022271536open in new window

1.6 websocket

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

推荐阅读:https://www.ruanyifeng.com/blog/2017/05/websocket.htmlopen in new window

挥手

1.7 四次挥手

四次挥手
四次挥手

A 和 B 打电话,通话即将结束后,A 说“我没啥要说的了”,B回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,这样通话才算结束。

1.8 为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次.

1.9 如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP设有一个活计时器,如果客户端没有发送请求,一直等待的话,则会白白浪费服务端请求,服务端每收到请求一次则会将活计时器重置,时间通常是设置为2小时,若2小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

推荐阅读:https://zhuanlan.zhihu.com/p/398890723open in new window

UDP

1.10 UDP的特点

1.11 TCP和 UDP的区别

TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。 TCP 不提供广播或多播服务。由于 TCP 要提供可靠的,面向连接的传输服务(TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源),这一难以避免增加了许多开销,如确认,流量控制,计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。TCP 一般用于文件传输、发送和接收邮件、远程登录等场景。

推荐阅读:https://www.cnblogs.com/williamjie/p/9390164.htmlopen in new window

1.12 UDP的应用场景

广播:因为其可以一对多进行发送,所以可用于广播

实时游戏:因为TCP如果丢包,则会等待这个包进行重发,这样就会卡住,有可能出现,恢复后,人已经死了的情况。

网页或者app的访问,QUIC

音视频