TCP/IP 是互联网相关的各类协议族的总称,其中包括 TCP,UDP,IP,FTP,HTTP,ICMP,SMTP 等。TCP/IP 中两个具有代表性的传输层协议是 TCP 和 UDP:
传输层:
传输层的两个主要协议:
概念: UDP(User Datagram Protocol)在 OSI 模型中处于传输层,属于无连接协议。UDP 尽最大可能交付,没有拥塞控制,面向报文,支持一对一、一对多、多对一和多对多的交互通信。
用户数据报协议 UDP 的特点:
(1)面向无连接:不需要像 TCP 一样在发送数据前进行三次握手,想发就直接发了,它只是数据的搬运工,不会对数据进行任何拆分和拼接操作。具体来说,就是在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了;在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作。
(2)有单播、多播、广播功能:支持一对一、一对多、多对多、多对一的方式传输方式。
(3)面向报文:所谓面向报文就是指UDP数据传输的单位是报文,且不会对数据作任何拆分和拼接操作。在发送端,应用程序给传输层的UDP什么样的数据,UDP不会对数据进行切分,只增加一个UDP头并交给网络层(IP层)。在接收端,UDP收到网络层的数据报后,去除IP数据报头部后遍交给应用层,不会作任何拼接操作。
(4)不可靠性:首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。UDP只会把想发的数据报文一股脑的丢给对方,并不在意数据有无安全完整到达。
(5)头部开销小:只有 8 字节,相比 TCP 的至少 20 个字节要少得多,在传输数据报文时是很高效的。UDP 头部包括:端口号 + 报文长度 + 数据报文的检验。
(6)没有拥塞控制:UDP始终以恒定的速率发送数据,并不会根据网络拥塞情况对发送速率作调整。这种方式有利有弊。弊端:网络拥塞时有些报文可能会丢失,因此UDP不可靠。优点:有些使用场景允许报文丢失,如:直播、语音通话,但对实时性要求很高,此时UDP还是很有用武之地的。
UDP报文头: 包括源端口,目的端口,整个数据报的长度,整个数据报的检验和。
概念: TCP(Transmission Control Protocol)是 面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流,每一条 TCP 连接只能是点对点的(一对一)的传输层通信协议。TCP将用户数据打包成报文段,它发送后会启动一个定时器。
传输控制协议 TCP 的特点:
(1)面向连接:面向连接,是指发送数据之前必须在两端建立连接。建立连接的方法是“三次握手”,这样能建立可靠的连接。建立连接,是为数据的可靠传输打下了基础。
(2)仅支持单播:每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。
(3)面向字节流:TCP 不像 UDP 一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。所谓面向字节流指的是TCP以字节为单位。虽然传输的过程中数据被划分成一个个数据报,但这只是为了方便传输,接收端最终接受到的数据将与发送端的数据一模一样。
(4)可靠传输:对于可靠传输,判断丢包,误码靠的是TCP的段编号以及确认号。TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。
(5)提供拥塞控制:当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞。
(6)提供全双工通信:TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据。当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于MSS)。
TCP头部: TCP头部长度有20字节的固定部分,选项部分长度不定,但最多40字节,因此TCP头部在20-60字节之间。
TCP连接与套接字:
TCP标识符(TCP Flags): TCP有 7 种标识符,用于表示TCP报文的性质。它们只能为 0 或 1
基本思想:让我知道你已经知道了
TCP 协议中,主动发起请求的一端称为客户端,被动连接的一端称为服务端。不管是客户端还是服务端,TCP 连接建立完后都能发送和接收数据。
最初服务器和客户端都为 CLOSED 状态。在通信开始前,双方创建各自的传输控制块(TCB)。
服务器创建完 TCB 后遍进入 LISTEN 状态,此时准备接收客户端发来的连接请求。
TCP 的三次握手还是挺有意思的,基本思想就是 “让我知道你已经知道” 了。 服务器监听请求,客户端发起连接请求(第一次连接),请求在路上可能存在丢失的风险, 所以当请求到了服务器后如果服务器同意建立连接会给客户端一个回信(第二次连接),告诉它:我已经收到请求,可以连接。 但是回信也存在一个问题,那就是回信能不能到客户端?它需要客户端给他一个回信说我已经收到批准通知了, 如果客户端一直不回复的话意味着客户端没有收到批准通知。 因此客户端一收到批准通知就立马回复(第三次握手):OK 老铁我收到你的批准通知了。至此,三次握手结束。
这种“让我知道你已经知道了”的想法是一种约定俗成的 可靠信息交互的基本方式, 基于此想法构建的信息交互框架叫做协议。
相关解释:
ACK、SYN 和 FIN这些大写的单词表示标志位,其值要么是 1,要么是 0;ack、seq小写的单词表示序号。
TCP连接是双向的,因此在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一方向的连接。
服务器结束 TCP 连接的时间要比客户端早一些。
TCP的可靠性表现在:它向应用层提供的数据是无差错的、有序的、无丢失的,简单的说就是:TCP最终递交给应用层的数据和发送者发送的数据是一模一样的。
TCP采用了流量控制、拥塞控制、连续ARQ等技术来保证它的可靠性。
ARQ(Automatic Repeat Request)自动重传请求。顾名思义,当请求失败时它会自动重传,直到请求被正确接收为止。这种机制保证了每个分组都能被正确接收。停止等待协议是一种 ARQ 协议。
停止等待协议的原理:
停止等待协议的注意点:
连续ARQ协议:在ARQ协议发送者每次只能发送一个分组,在应答到来前必须等待。而连续ARQ协议的发送者拥有一个发送窗口,发送者可以在没有得到应答的情况下连续发送窗口中的分组。这样降低了等待时间,提高了传输效率。(TCP保证其可靠性采用的是滑动窗口协议,停止等待协议是它的简化版)
累计确认:在连续ARQ协议中,接收者也有个接收窗口,接收者并不需要每收到一个分组就返回一个应答,可以连续收到分组之后统一返回一个应答。这样能节省流量。TCP头部的ack字段就是用来累计确认,它表示已经确认的字节序号+1,也表示期望发送者发送的下一个分组的起始字节号。
发送窗口:发送窗口的大小由接收窗口的剩余大小决定。接收者会把当前接收窗口的剩余大小写入应答 TCP 报文段的头部,发送者收到应答后根据该值和当前网络拥塞情况设置发送窗口的大小。发送窗口的大小是不断变化的。
发送窗口由三个指针构成:p1,p2,p3
p1-p2 间的字节表示已经发送,但还没收到确认应答。这部分的字节仍需保留,因为可能还要超时重发。p2-p3 间的字节表示可以发送,但还没有发送的字节。发送者每收到一个应答,后沿就可以向前移动指定的字节。此时若窗口大小仍然没变,前沿也可以向前移动指定字节。
接收窗口:接收者收到的字节会存入接收窗口,接收者会对已经正确接收的有序字节进行累计确认,发送完确认应答后,接收窗口就可以向前移动指定字节。如果某些字节并未按序收到,接收者只会确认最后一个有序的字节,从而乱序的字节就会被重新发送。
连续 ARQ 的注意点:
什么是流量控制?
如果发送者发送过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。
流量控制的目的?
流量控制根本目的是防止分组丢失,它是构成 TCP 可靠性的一方面。
如何实现流量控制?
由滑动窗口协议(连续ARQ协议)实现。
滑动窗口协议既保证了分组无差错、有序接收,也实现了流量控制。
流量控制引发的死锁
当发送者收到了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。但是如果这个窗口不为0的应答在传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方就相互等待,从而产生死锁。
持续计时器
为了避免流量控制引发的死锁,TCP 使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。
“拥塞避免” 并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。“拥塞避免”是说在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。
拥塞控制 和 流量控制 的区别?
拥塞控制是针对于网络而言的,它是防止往网络中写入太多分组,从而导致网络拥塞的情况;而流量控制是针对接收者的,它是通过控制发送者的发送速度保证接收者能够来得及接收。
拥塞控制的目的?
拥塞控制方法:慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)和快恢复( fast recovery )。
发送方维持一个拥塞窗口 cwnd ( congestion window )的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞。
发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。
慢开始:当主机开始发送数据时,如果立即所大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。因此,较好的方法是 先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd(congestion window)设置为一个最大报文段 MSS(Maximum Segment Size)的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口数值翻倍。用这样的方法逐步增大发送方的拥塞窗口(cwnd),可以使分组注入到网络的速率更加合理。
每经过一个传输轮次,拥塞窗口 cwnd 就加倍。一个传输轮次所经历的时间其实就是往返时间RTT。不过“传输轮次”更加强调:把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。
若发送方出现了超时重传,则表明网络出现拥塞。此时:
另外,慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大cwnd。
为了防止拥塞窗口(cwnd)增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量(如何设置ssthresh)。慢开始门限ssthresh的用法如下:
慢开始算法的作用:慢开始算法将发送窗口从小扩大,而且按指数级扩大,从而避免一开始就往网络中注入过多的分组从而导致拥塞;它将窗口慢慢扩大的过程其实也在探测网络拥塞情况的过程,当发现出现拥塞时,及时降低发送速度,从而减缓网络拥塞。
拥塞避免算法:让拥塞窗口(cwnd)缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口(cwnd)加 1,而不是加倍。这样拥塞窗口(cwnd)按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。
如下图,用具体数值说明了上述拥塞控制的过程。现在发送窗口的大小和拥塞窗口一样大。
拥塞避免算法的作用:拥塞避免算法使发送窗口以线性方式增长,而非指数级增长,从而使网络更加不容易发生拥塞。
AIMD算法(加法增大乘法减小算法):慢开始算法 和 拥塞避免算法 还有个名称叫做加法增大乘法减小算法。
慢开始算法和拥塞避免算法能保证网络出现拥塞时进行相应的处理,而快重传和快恢复是一种拥塞预防的方式,此时网络可能尚未出现拥塞,但已经有拥塞的征兆,因此得作出一些预防措施。
如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。这时,TCP马上把拥塞窗口 cwnd 减小到1,并执行慢开始算法,同时把慢开始门限值ssthresh减半。这是不使用快重传的情况。
快重传原理:因为TCP具有累计确认的能力,因此接收者收到一个分组的时候不会立即发出应答,可能需要等待收到多个分组之后再同一发出累计确认。但快重传算法就要求,接收者如果接收到一个乱序的分组的话,就必须立即发出前一个正确分组的确认应答,这样能让发送者尽早地知道有一个分组可能丢失。
快重传算法 首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。
接收方收到了M1和M2后都分别发出了确认。现在假定接收方没有收到M3但接着收到了M4。显然,接收方不能确认M4,因为M4是收到的失序报文段。根据 可靠传输原理,接收方可以什么都不做,也可以在适当时机发送一次对M2的确认。但按照快重传算法的规定,接收方应及时发送对M2的重复确认,这样做可以让 发送方及早知道报文段M3没有到达接收方。发送方接着发送了M5和M6。接收方收到这两个报文后,也还要再次发出对M2的重复确认。这样,发送方共收到了 接收方的四个对M2的确认,其中后三个都是重复确认。快重传算法还规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必 继续等待M3设置的重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。
快重传算法规定:发送端只要一连收到三个重复的 ACK 即可断定有分组丢失了,就应该立即重传丢失的报文段而不必继续等待为该报文段设置的重传计时器的超时。
快恢复原理:当发送者收到同一个分组的三个确认应答后,就基本可以判断这个分组已经丢失了;这时候无需等待超时,直接执行『乘法减小加法增大』:
与快重传配合使用的是快恢复算法,其过程有以下两个要点:
乘法减小:是指不论在慢开始阶段还是拥塞避免阶段,只要出现一次超时(即出现一次网络拥塞),就把慢开始门限值 ssthresh 设置为当前的拥塞窗口值乘以 0.5。当网络频繁出现拥塞时,ssthresh 值就下降得很快,以大大减少注入到网络中的分组数。
加法增大:是指执行拥塞避免算法后,在收到对所有报文段的确认后(即经过一个往返时间),就把拥塞窗口 cwnd 增加一个 MSS 大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞。
快重传和快恢复的示意图:新的 TCP Reno 版本在快重传之后采用快恢复算法而不是采用慢开始算法
在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用。采用这样的拥塞控制方法使得TCP的性能有明显的改进。
也有的快重传实现是把开始时的拥塞窗口cwnd值再增大一点,即等于 ssthresh + 3 X MSS 。这样做的理由是:既然发送方收到三个重复的确认,就表明有三个分组已经离开了网络。这三个分组不再消耗网络 的资源而是停留在接收方的缓存中。可见现在网络中并不是堆积了分组而是减少了三个分组。因此可以适当把拥塞窗口扩大了些。
接收方根据自己的接收能力设定了接收窗口rwnd,并把这个窗口值写入TCP首部中的窗口字段,传送给发送方。因此,接收窗口又称为通知窗口。因此,从接收方对发送方的流量控制的角度考虑,发送方的发送窗口一定不能超过对方给出的接收窗口rwnd 。
发送方窗口的上限值 = Min [ rwnd, cwnd ]
1)为什么用三次握手?
答: 防止失效的连接请求报文段被服务端接收,从而产生错误。如果客户端发送的连接请求在网络中滞留太久,客户端等待一个超时重传时间后,就会重新请求连接。只要有三次握手,服务器虽然收到了两个连接请求,并回发了两个请求确认,但客户端不会回应前一个请求确认,就不会打开这个失效的链接请求。
失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是失效的。
2)为什么不能用两次握手进行连接?
答: 三次握手完成两个重要的功能,既:1)双方都知道彼此已准备好,2)允许双方就初始序列号进行协商,这个序列号在握手过程中进行发送和确认。
如果把三次握手改成两次握手,可能发生死锁。比如:客户端发出去的一个连接请求由于某些原因在网络节点中滞留导致延迟,直到连接释放的某个时间点才到达服务端,但这是一个早已失效的报文,可是这时服务端仍然认为这是客户端的建立连接请求第一次握手,于是服务端回应了客户端,这是第二次握手。但是客户端并不会发来新的数据,服务端就这么傻等着,形成了死锁。
3)如果已经建立了连接,但是客户端突然出现故障了怎么办?
答: TCP 还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2 小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75 秒钟发送一次。若一连发送 10 个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
4)为什么用四次挥手?
答: 服务器收到客户端发送的FIN 连接释放报文之后,就进入了 CLOSE-WAIT 状态,发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
5)为什么客户端要先进入TIME-WAIT状态,等待2MSL后才进入CLOSED状态?
答: 为了保证B能收到A的确认应答。若A发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,B等待超时后就会重新发送连接释放请求,但此时A已经关闭了,不会作出任何响应,因此B永远无法正常关闭。
6)为什么连接的时候是三次握手,关闭的时候却是四次握手?
答: 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
7)为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答: 虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
9)在浏览器中输入 www.baidu.com 后的执行过程?用到哪些层?各层是干什么的?
浏览器要将URL解析为IP地址,解析域名就要用到DNS协议,首先主机会查询DNS的缓存,如果没有就给本地DNS发送查询请求。DNS查询分为两种方式,一种是递归查询,一种是迭代查询。如果是迭代查询,本地的DNS服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名服务器发送查询请求,然后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。
得到IP地址后,浏览器就要与服务器建立一个http连接。因此要用到http协议,http协议报文格式上面已经提到。http生成一个get请求报文,将该报文传给TCP层处理,所以还会用到TCP协议。如果采用https还会使用https协议先对http数据进行加密。TCP层如果有需要先将HTTP数据包分片,分片依据路径MTU和MSS。TCP的数据包然后会发送给IP层,用到IP协议。IP层通过路由选路,一跳一跳发送到目的地址。当然在一个网段内的寻址是通过以太网协议实现(也可以是其他物理层协议,比如PPP,SLIP),以太网协议需要直到目的IP地址的物理地址,有需要ARP协议。
1、客户端浏览器通过 DNS 解析到 www.baidu.com 的 IP 地址 220.181.27.48,通过这个 IP 地址找到客户端到服务器的路径。客户端浏览器发起一个 HTTP 会话到 220.181.27.48,然后通过 TCP 进行封装数据包,输入到网络层。
2、在客户端的传输层,把HTTP会话请求分成报文段,添加源和目的端口,如服务器使用80端口监听客户端的请求,客户端由系统随机选择一个端口如5000,与服务器进行交换,服务器把相应的请求返回给客户端的5000端口。然后使用IP层的IP地址查找目的端。
3、客户端的网络层不用关心应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的描述,无非就是通过查找路由表决定通过那个路径到达服务器。
4、客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定IP地址的MAC地址,然后发送ARP请求查找目的地址,如果得到回应后就可以使用ARP的请求应答交换的IP数据包现在就可以传输了,然后发送IP数据包到达服务器的地址。
其中,DNS协议,http协议,https协议属于应用层;TCP/UDP属于传输层;IP协议,ARP协议属于网络层。
参考资料:
[1] 计算机网络传输层知识点全覆盖
[2] TCP/IP详解–拥塞控制 & 慢启动 快恢复 拥塞避免
[3] TCP的三次握手与四次挥手理解及面试题(很全面)
[4] 一文搞懂 TCP 和 UDP 的区别