力推TCP协议面试篇(基础详细)

参考https://blog.csdn.net/mulinsen77/article/details/88925672
好文: https://www.zhihu.com/question/24853633

附:TCP是什么及特点

  • TCP即传输控制协议(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通讯协议。

  • 特点:当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文。之后TCP把数据包传递给IP层,由它来通过网络将包传送给接收端实体的TCP层

  • (1)基于流的方式;两个应用程序通过TCP交换8bit字节构成的字节流,TCP不在字节流中插入记录标识符。我们将这称为字节流服务( byte stream service)。

  • (2)面向连接;面向连接即意味着两个使用TCP的应用(通常为服务器与客户端)在彼此交换数据之前必须先建立一个TCP连接。

(3)可靠通信方式(可靠性);

TCP通过下列方式提供可靠性:
1.应用数据被分割成TCP认为最适合发送的数据块。
2.当TCP发出一个段后.它启动一个保活定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
3.当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒。
4.TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
5. 既然TCP报文段作为I P数据报来传输,而 I P数据报的到达可能会失序,因此 TCP报文段的到达也可能会失序。如果必要, TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
6.既然I P数据报会发生重复,TCP的接收端必须丢弃重复的数据。
7.TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

(4)在网络情况不佳的时候尽量降低系统由于重传带来的带宽开销;
(5)通信连接维护是面向的两个端点的,而不考虑中间网段和节点。

面试问:为啥三次握手而不是两次?

TCP在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立通过三次握手释放则需要四次握手,所以说每个连接的建立都是需要资源消耗和时间消耗的。

三次握手协议建立连接:当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对对方的SYN执行ACK确认。这种建立连接的方法可以防止产生错误的连接,TCP使用的流量控制协议是可便大小的华东窗口协议。
在这里插入图片描述

TCP三次握手的过程如下:
第一次握手:建立连接时,客户端发送首部中的同部位syn(/ˈsɪŋkrənaɪz/ )包(seq=x)到服务器,并进入SYN_SENT状态(同步已发送),等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态(同步收到)
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

疑问:为什么上面参数+1的操作

这里面所有的ACK 都是收到的一个SYN 值 + 1,这个+1 是因为SYN 占据一个字节的序列号空间,所以每一个SYN 的ACK 中的确认号都是该SYN的初始序列号+1.

同样的,每一个FIN 的ACK 中的确认号也为该 FIN 的序列号 +1

上面参数讲解一波

序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。

确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。

确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效

同步SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1。ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。

终止FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接

ACK、SYN和FIN这些参数表示标志位,其值要么是1,要么是0;ack、seq表示序号。
在这里插入图片描述
总结:目的是 “为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”,这个只能算是表因,并不涉及本质。

谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段” 的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。
假设不采用 “三次握手”,那么只要 server 发出确认,新的连接就建立了。由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用 “三次握手” 的办法可以防止上述现象发生。
例如刚才那种情况,client 不会向 server的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。”

TCP 需要 seq 序列号来做可靠重传或接收,而避免连接复用时无法分辨出 seq 是延迟或者是旧链接的 seq,因此需要三次握手来约定确定双方的 ISN(初始 seq 序列号)。

TCP 设计中一个基本设定就是,通过TCP 连接发送的每一个包,都有一个sequence number。而因为每个包都是有序列号的,所以都能被确认收到这些包。确认机制是累计的,所以一个对sequence number X 的确认,意味着 X 序列号之前(不包括 X) 包都是被确认接收到的。

TCP 协议是不限制一个特定的连接(两端 socket 一样)被重复使用的。

所以这样就有一个问题:这条连接突然断开重连后,TCP 怎么样识别之前旧链接重发的包?——这就需要独一无二的 ISN(初始序列号)机制。
当一个新连接建立时,初始序列号( initial sequence number ISN)生成器会生成一个新的32位的 ISN。
这个生成器会用一个32位长的时钟,差不多4µs 增长一次,因此 ISN 会在大约 4.55 小时循环一次

(232位的计数器,需要2324 µs才能自增完,除以1小时共有多少µs便可算出2^324 /(1606010001000)=4.772185884 )

而一个段在网络中并不会比最大分段寿命(Maximum Segment Lifetime (MSL) ,默认使用2分钟)长,MSL 比4.55小时要短,所以我们可以认为 ISN 会是唯一的。发送方与接收方都会有自己的 ISN (下面的例子中就是 X 与 Y)来做双方互发通信,具体的描述如下:

三次握手(A three way handshake)是必须的, 因为 sequence numbers(序列号)没有绑定到整个网络的全局时钟(全部统一使用一个时钟,就可以确定这个包是不是延迟到的)以及 TCPs 可能有不同的机制来选择 ISN(初始序列号)。

接收方接收到第一个 SYN 时,没有办法知道这个 SYN 是是否延迟了很久了,除非他有办法记住在这条连接中,最后接收到的那个sequence numbers(然而这不总是可行的)。

这句话的意思是:一个 seq 过来了,跟现在记住的 seq 不一样,我怎么知道他是上条延迟的,还是上上条延迟的呢?所以,接收方一定需要跟发送方确认 SYN。

面试:为啥关闭的时候却是四次握手

1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

TCP报文的首部长度以及都有哪些字段

最少20字节,因为TCP的头部中20字节的首部是固定的,如下图:
在这里插入图片描述
在这里插入图片描述
附:
在这里插入图片描述

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

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

猜你喜欢

转载自blog.csdn.net/weixin_42754971/article/details/113643245