TCP、UDP以及面试常见问题

TCP、UDP以及面试常见问题,第1张

1.UDP:

UDP是一个简单的面向数据报的运输层协议:进程的每个输出 *** 作都正好产生一个UDP数据报,并组装成一份待发送的 IP数据报。这与面向流字符的协议不同,如TCP,应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联系。

1. UDP协议端格式:

2.UDP的特性:

1.无连接:没有建立连接就发数据
2.不可靠:没有类似TCP保证数据传输的安全机制,(连接管理机制,确认应答机制,超时机制)效率更高。
3.面向数据报:只能一次接收(系统级别的 *** 作:调用系统函数)
4.没有发送缓冲区(发了消息就不管),有接收缓冲区
5.数据最大为64k

如何使UDP变得可靠?
1.加入确认应答机制。
2.加入连接管理机制。
3.加入超时重传机制。

2.TCP:

尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务。
TCP提供一种面向连接的、可靠的字节流服务。
设计TCP协议的理念:非100%安全,保证可承受范围内的安全,尽可能的提高网络传输数据的效率。

1.TCP协议端格式:


六位标志位:
URG: 紧急指针是否有效
ACK: 确认号是否有效
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段
SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段
FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段重点掌握ACK,SYN,FIN

2.TCP机制: (1)确认应答机制:

主机A发送数据给主机B,每个数据都带了数据序号,主机B返回ACK应答
每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发

作用:
1.保证安全:保证‘我’发送的消息,对方必须确认并恢复
2.保证多条数据确认信息的安全(告诉发送者,这次回应是对哪些数据,下次数据发送应该从什么时候开始)

(2)超时重传:


当发送端发送数据时,在一段时间内,没有接受到该条数据的确认应答信息,就会重新发送这条信息。
没有收到确认应答的情况:1.主机A的数据报在发送的过程中丢了。2.主机B的ACK应答丢了

超时时间的确定:TCP会根据当时的网络状态,动态的计算数据发送的速度,得到单次数据报发送的最大生存时间(MSL),超时时间即为(2MSL)

了解:如果一直接收不到ACK,超时时间会如何处理?
Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍.
如果重发一次之后, 仍然得不到应答, 等待 2500ms 后再进行重传.
如果仍然得不到应答, 等待 4500ms 进行重传. 依次类推, 以指数形式递增(2的指数倍).
累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接.

(3)连接管理机制:

就是大家所熟知的TCP三次握手,四次挥手。
三次握手:
刚开始客户端处于 closed 的状态,服务端处于 listen 状态。然后

  1、第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN(c)。此时客户端处于 SYN_Send 状态。

  2、第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s),同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。

  3、第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。

  4、服务器收到 ACK 报文之后,也处于 establised 状态,此时,双方以建立起了链接。

连接建立过程如图:

  • 四次挥手:

        1、第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态。                    
        2、第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为ACK报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态。   
        3、第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于LAST_ACK 的状态。 
        4、第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK报文之后才会进入CLOSED 状态 
        5、服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
        ![在这里插入图片描述](http://www.kaotop.com/file/tupian/20220427/e3d05131099c400e90f6a8f31e66d3a0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Li_5a6J5qGl,size_20,color_FFFFFF,t_70,g_se,x_16)
    

具体过程可以参考:添加链接描述
TCP整个过程状态变换:

(4)滑动窗口:

TCP的滑动窗口是以字节为单位的。

TCP原有的应答机制使其在发送后,需要接受应答才能继续工作,利用滑动窗口机制可大幅提高发送效率。
滑动窗口:在窗口未满时,不用接收ACK应答就可以持续发送信息,在接收到ACK后,窗口向后滑动。

*** 作系统内核为了维护这个滑动窗口, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答;只有确认应答过的数据, 才能从缓冲区删掉;

窗口大小:
由拥塞窗口和流量控制窗口决定(滑动窗口大小=(拥塞窗口大小,流量控制大小))

窗口越大, 则网络的吞吐率就越高

为什么要有接收缓冲区和发送缓冲区:
发送端的发送缓冲区:记录已经发送的数据——搜到对应的ACK应答,才可以清理该数据
接收端的接收缓冲区:记录已经接收的数据——如果发送数据报丢包,才知道让对方重发

详细解释可参考:https://blog.csdn.net/qq_45704528/article/details/118635841

(5)流量控制机制:

接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.

接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端;
窗口大小字段越大, 说明网络的吞吐量越高;

  • 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;

  • 发送端接受到这个窗口之后, 就会减慢自己的发送速度; 如果接收端缓冲区满了, 就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端.

当接收端使用流量控制窗口时,如何保证接受端的数据安全?
告诉发送端,影响发送端滑动窗口的大小

(6)拥塞控制机制

在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的有效部分,网络的性能就要变坏。这种情况就叫做拥塞(congestion)。

拥塞控制与流量控制的关系密切,它们之间也存在着一些差别。所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。

1999年公布的因特网建议标准 RFC 2581定义了进行拥塞控制的四种算法,即 慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)和快恢复(fast recovery)。 以后RFC 2582和RFC 3390又对这些算法进行了一些改进。
发送方维持一个叫做拥塞窗口cwnd (congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口。以后我们就知道,如果再考虑到接收方的接收能力,那么发送窗口还可能小于拥塞窗口。
发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。

  • 慢开始算法的思路是这样的。当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。经验证明,较好的方法是先探测-一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。
    下面用例子说明:

    下面用例子说明慢开始算法的原理。
    为方便起见,我们用报文段的个数作为窗口大小的单位(请注意,实际上 TCP是用字节作为窗口的单位),这样可以使用较小的数字来说明拥塞控制的原理。
    在一开始发送方先设置cwnd = 1,发送第一个报文段M,接收方收到后确认M。发送方收到对M的确认后,把cwnd 从1增大到2,于是发送方接着发送M和 M两个报文段。接收方收到后发回对M,和 M,的确认。发送方每收到一个对新报文段的确认(重传的不算在内)就使发送方的拥塞窗口加1,因此发送方在收到两个确认后,cwnd 就从2增大到4,并可发送M ~M,共4个报文段。因此使用慢开始算法后,每经过一个传输轮次(transmission round),拥塞窗口cwnd就加倍。

为了防止拥塞窗口 cwnd 增长过大引起网络拥塞,还需要设置一个慢开始门限 ssthresh状态变量(如何设置ssthresh,后面还要讲)。

  • 慢开始门限当cwnd < ssthresh时,使用上述的慢开始算法。

  • 当cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。

  • 当cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。

拥塞避免算法的思路是让拥塞窗口 cwnd缓慢地增大,即每经过一个往返时间RTT 就把发送方的拥塞窗口 cwnd 加19,而不是加倍。这样,拥塞窗口cwnd 按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。
如图所示:

当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长
引入快重传和快恢复:

  • 快重传算法 首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等待自己发送数据时才进行捎带确认。
  • 快回复算法(1)当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把慢开始门限ssthresh 减半。这是为了预防网络发生拥塞。请注意,接下去不执行慢开始算法。
    (2)由于发送方现在认为网络很可能没有发生拥塞(如果网络发生了严重的拥塞,就不会一连有好几个报文段连续到达接收方,就不会导致接收方连续发送重复确认),因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
(7)延迟应答机制:

举个例子:
假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;
但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;

延迟应答类型:
数量限制: 每隔N个包就应答一次;
时间限制: 超过最大延迟时间就应答一次;

(8)捎带机制:

在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的,意味着当客户端给服务端发送请求时,服务端会给客户端响应数据,此时ACK就像可以搭请求数据的顺风车,一起发送。

接收端响应的ACK,和主动发送的数据,可以合并返回。

3.常见问题: 1.TCP------>三次握手中的问题:

1.syn为什么有两个?
双方的连接状态会持续,且连接是有方向的

2.第二步中,为什么是ack+syn?
本质上是一个发ack应答,一个发syn请求,而且是方向一致的两个数据报,可以合并

3.第三步中,ack确认应答哪个?
应答第二步的syn

4.(ISN)是固定的吗?
三次握手的一个重要功能是客户端和服务端交换ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。
5.什么是半连接队列

服务器第一次收到客户端的 SYN 之后,就会处于SYN_RCVD状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
6.三次握手过程中可以携带数据吗

很多人可能会认为三次握手都不能携带数据,其实第三次握手的时候,是可以携带数据的。也就是说,第一次、第二次握手不可以携带数据,而第三次握手是可以携带数据的。(发送端认为已建立连接)。

2.TCP------>四次挥手中的问题:

1.为什么客户端发送 ACK 之后不直接关闭,而是要等一阵子才关闭(TIME_WAIT状态)?

要确保服务器是否已经收到了我们的 ACK 报文,如果没有收到的话,服务器会重新发 FIN 报文给客户端,客户端再次收到 ACK 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文。

2.为什么不把第三次挥手不和第两次挥手合并,即建立连接时一起传输(三次握手),释放连接时却要分开传输(四次挥手)?

  • 第2步是TCP协议在系统内核中实现时,自动响应的ack
  • 第3步时应用程序手动调用close来关闭连接的程序在关闭连接之前,可能需要执行释放资源等前置 *** 作,所以不能合并(TCP协议实现时,没有这样进行设计)

3.TIME_WAIT过多有什么危害?

  • 服务端受内存资源占用当服务端有过多的的TCP连接时,虽然理论上可以建立很多连接,因为一个服务端只监听一个端口,不会导致端口资源受限。但是tcp连接需要占用系统资源,比如cpu资源,文件描述符,线程资源等等
  • 客户端受端口资源的占用: 一个tcp占用一个发起连接方的一个本地端口,如果tcp连接过多,则会导致端口资源不足,无法建立新连接

4、TIME_WAIT的时间?

就是2个报文最长生存时间(2MSL),1个MSL在RFC上建议是2分钟,而实现传统上使用30秒,因而,TIME_WAIT状态一般维持在1-4分钟。
  
5.如何优化TIME_WAIT过多的问题?
两种方法:
1.调整系统内核参数
2。保持和server的长连接
具体详情可以参考:https://cloud.tencent.com/developer/article/1589962

5.当关闭连接最后一个ACK丢失怎么办?

如果最后一个ACK丢失的话,TCP就会认为它的FIN丢失,进行重发FIN。在客户端收到FIN后,就会设置一个2MSL计时器,2MSL计时器可以使客户等待足够长的时间,使得在ACK丢失的情况下,可以等待下一个FIN的到来。如果在TIME_WAIT状态内有一个新的FIN到达了,客户就会发送一个新的ACK,并重新设置2MSL计时器。

如果重传FIN到达客户端时,客户端已经进入CLOSED状态时,那么客户就永远收不到这个重传的FIN报文段,服务器收不到ACK,服务器无法关闭连接。

3.TCP建立连接之后怎么保持连接(检测连接断没断)?

有两种技术可以运用。一种是有TCP协议层实现的Keepalive机制,另一种是由应用层自己实现的HeartBeat心跳包。

1)在TCP中有一个Keep-alive的机制可以检测死连接,原理很简单,当连接闲置一定的时间(参数值可以设置,默认是2个小时)之后,TCP协议会向对方发一个keepalive探针包(包内没有数据),对方在收到包以后,如果连接一切正常,则应当回复一个ACK;如果连接出现错误了(例如对方重启了,连接状态丢失),则应当回复一个RST;如果对方没有回复,那么,服务器每隔一定的时间(参数值可以设置)再发送keepalive探针包,如果连续多个包(参数值可以设置)都被无视了,说明连接被断开了。

2)心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。由应用程序自己发送心跳包来检测连接的健康性。客户端可以在一个Timer中或低级别的线程中定时向服务器发送一个短小精悍的包,并等待服务器的回应。客户端程序在一定时间内没有收到服务器回应即认为连接不可用,同样,服务器在一定时间内没有收到客户端的心跳包则认为客户端已经掉线。

4.如何处理TCP粘包问题:

粘包问题的本质就是数据读取边界错误所致。
 1.定长发送:
 在进行数据发送时采用固定长度的设计,也就是无论多大数据发送都分包为固定长度(为便于描述,此处定长为记为LEN),也就是发送端在发送数据时都以LEN为长度进行分包。这样接收方都以固定的LEN进行接收,如此一来发送和接收就能一一对应了。分包的时候不一定能完整的恰好分成多个完整的LEN的包,最后一个包一般都会小于LEN,这时候最后一个包可以在不足的部分填充空白字节。
 2.尾部标记序列:
 在每个要发送的数据包的尾部设置一个特殊的字节序列,此序列带有特殊含义,跟字符串的结束符标识”\0”一样的含义,用来标示这个数据包的末尾,接收方可对接收的数据进行分析,通过尾部序列确认数据包的边界。
 3.头部标记分步接收:(最实用)
 定义一个用户报头,在报头中注明每次发送的数据包大小。接收方每次接收时先以报头的size进行数据读取,这必然只能读到一个报头的数据,从报头中得到该数据包的数据大小,然后再按照此大小进行再次读取,就能读到数据的内容了。这样一来,每个数据包发送时都封装一个报头,然后接收方分两次接收一个包,第一次接收报头,根据报头大小第二次才接收数据内容。

具体详情可以参考:

https://blog.csdn.net/m0_37829435/article/details/81747488
写在最后:
关于网络这方面,应用层的HTTP和HTTPS,以及TCP和UDP是很重要的,可以看看计算机网络第五版 谢希仁这一版,和TCP-IP详解卷,这部分还是要多总结和理解,好了,暂时想到的就只有这些,其他想到了以后再写。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/742510.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存