TCP/IP 杂记

在这里插入图片描述

三次握手

为什么不是两次握手?

如果两次握手,当client发送SYN后,SYN包因为某些原因,经过超时的时间之后才到达server,此时client返回ACK包,而client早已进入CLOSE状态,而client以为连接已经建立,等待client传送数据。
导致失败连接白白占用了资源。

第三次握手失败怎么办?

可以看出当失败时服务器并不会重传ack报文,而是直接发送RTS报文段,进入CLOSED状态。这样做的目的是为了防止SYN洪泛攻击。
另一种说法就是Linux下默认会进行5次重发SYN-ACK包,每次时间指数退避(1s,2s,4s…),第五个包没有响应之后TCP才会断开这个连接。

TCP/IP详解上面写的是第一种

建立连接时出现四次握手的情况

当Peer两端同时发起SYN来建立连接时,就出现了四次握手来建立连接(对于有些TCP/IP的实现,可能不支持这种同时打开的情况)
在这里插入图片描述

四次挥手

为什么需要TIME_WAIT?

TIMEWAIT状态也称为2MSL等待状态。

MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
TTL与MSL是有关系的但不是简单的相等的关系,MSL要大于等于TTL。

1)为实现TCP这种全双工(full-duplex)连接的可靠释放
当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包,保证可靠释放。

2)为使旧的数据包在网络因过期而消失
每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。

在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。还有IME_WAIT的快速回收和重用,这里不作深入了。

Client和Server同时发起断开连接的FIN包会怎么样呢,TCP状态是怎么转移的?

在这里插入图片描述

正常情况:TCP的Peer端在收到对端的FIN包前发出了FIN包,那么该Peer的状态就变成了FIN_WAIT1。
Peer在FIN_WAIT1状态下收到对端Peer对自己FIN包的ACK包的话,那么Peer状态就变成FIN_WAIT2。
Peer在FIN_WAIT2下收到对端Peer的FIN包,在确认已经收到了对端Peer全部的Data数据包后,就响应一个ACK给对端Peer,然后自己进入TIME_WAIT状态。

但是如果Peer在FIN_WAIT1状态下首先收到对端Peer的FIN包的话,那么该Peer在确认已经收到了对端Peer全部的Data数据包后,就响应一个ACK给对端Peer,然后自己进入CLOSEING状态,Peer在CLOSEING状态下收到自己FIN包的ACK包的话,那么就进入TIME WAIT状态。

经过2MSL时间后CLOSED。

关闭TCP一定要四次挥手吗

不一定,4次挥手关闭TCP连接是最安全的做法。但有时是不太希望出现TIME_WAIT 状态(比如当MSL数值设置过大导致服务器端有太多TIME_WAIT状态的TCP连接,减少这些条目数可以更快地关闭连接,为新连接释放更多资源),这时我们可以通过设置SOCKET变量的SO_LINGER标志来避免SOCKET在close()之后进入TIME_WAIT状态,这时将通过发送RST强制终止TCP连接(取代正常的TCP四次握手的终止方式)。但这种方法并不优先选择,使用TIME_WAIT的方法是优先考虑的。

如果Server在收到Client的FIN包后,再也没数据需要发送给Client了,那么对Client的ACK包和Server自己的FIN包就可以合并成一个包发送过去,这样四次挥手就可以变成三次了


数据传输

确认丢失和确认迟到

确认丢失:发送的包在超时时间内没有收到确认。
确认迟到:发送的包在超时时间外收到确认(因为已经超时,所以此时已经重传),发送端收到确认不做事,如果接收端收到重复的包则丢弃。

ARQ协议

定义:
可靠传输协议常称为自动重传请求ARQ (Automatic Repeat reQuest),通过接收方请求发送方重传出错的数据报文来恢复出错的报文。

  • 停等式ARQ
    在停等式ARQ中,数据报文发送完成之后,发送方等待接收方的状态报告,如果状态报告报文发送成功,发送后续的数据报文,否则重传该报文。
    停等式ARQ,发送窗口和接收窗口大小均为1,发送方每发送一帧之后就必须停下来等待接收方的确认返回,仅当接收方确认正确接收后再继续发送下一帧。该方法所需要的缓冲存储空间最小,缺点是信道效率很低。

  • 连续ARQ协议
    由于停止等待ARQ协议信道利用率太低,所以需要使用连续ARQ协议来进行改善。这个协议会连续发送一组数据包,然后再等待这些数据包的ACK。一般采用积累确认方式,那就会使用GBN;否则使用选择性重传。

    • 回退n帧的ARQ(go-back-n/GBN)
      发信侧不用等待收信侧的应答,持续的发送多个帧,假如发现已发送的帧中有错误发生,那么从那个发生错误的帧开始及其之后所有的帧全部再重新发送。
      特点:复杂度低,但是不必要的帧会再重发,所以大幅度范围内使用的话效率是不高的
      例:如果序列号有K bits,那么这个ARQ的协议大小为:2^k-1。(收到哪个就返回哪个)

    • 选择性重传ARQ协议
      发信侧不用等待收信侧的应答,持续的发送多个帧,假如发现已发送的帧中有错误发生,那么发信侧将只重新发送那个发生错误的帧。
      特点:相对于GBN 复杂度高,但是不需要发送没必要的帧,所以效率高。
      例:如果序列号有K bits,那么这个ARQ的协议大小为:2^(k-1)
      关于2^(k-1): (假设序号最大为7即0,1,2,3,4,5,6,7,发送窗口大小为5,当发送窗口发送0,1,2,3,4后,假设接收窗口全部收到,则接收窗口向前移动到5次,接受窗口期望接收5,6,7,0,1.若发送窗口并没接收到任何ACK,所以发送窗口重发0,1,2,3,4此时接收窗口会以为重发的0,1是新的分组。所以此时如果发送窗口大小是4,发送4个分组后,全部收到而ACK全部丢失,窗口移动至5-8,如果接收方收到了,认出5-8是新分组,返回8,不会与上一次丢失的分组混淆)

SACK选择性确认(SACK是选择性重传ARQ协议的接收方行为)

SACK是TCP选项,它使得接收方能告诉发送方哪些报文段丢失,哪些报文段重传了,哪些报文段已经提前收到等信息。根据这些信息TCP就可以只重传哪些真正丢失的报文段。(其扩展是D-SACK)

需要注意的是只有收到失序的分组时才会可能会发送SACK,TCP的ACK还是建立在累积确认的基础上的。也就是说如果收到的报文段与期望收到的报文段的序号相同就会发送累积的ACK,SACK只是针对失序到达的报文段的。

TCP快速重传

如果收到一个out-of-order的报文段时, TCP需要立刻产生一个ACK,这个ACK不应该被延时,目的在于让对方知道收到一个失序的报文,并告诉对方自己希望收到的报文seq,我们不知道这个重复的ACK的原因,因为还是会等待少量的重复ACK到来,如果连续收到3个或者3个以上的dup ACK,就被判断这个报文被丢失了,于是就需要立即重传丢失的数据段,这个地方不用等待定时器溢出。

两次duplicated ACK时很可能是乱序造成的!三次duplicated ACK 时很可能是丢包造成的!四次duplicated ACK更更更可能是丢包造成的!但是这样的响应策略太慢(折中)。丢包肯定会造成三次duplicated ACK!综上是选择收到三个重复确认时窗口减半效果最好,这是 实践经验 …。


Other

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

这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,我们也未必全部数据都发送给对方了,所以我们不可以立即close,也可以发送一些数据给对方后(缓冲区未发送的),再发送FIN报文给对方来表示同意现在关闭连接,因此,我们的ACK和FIN一般都会分开发送。

滑动窗口协议

TCP 连接的每一端都必须设有两个窗口——一个发送窗口和一个接收窗口。TCP 的可靠传输机制用字节的序号进行控制,窗口是随着时间变化可以向前滑动的。TCP 所有的确认都是基于序号而不是基于报文段。TCP的标准窗口是一个16bit位字段,所以窗口最大为2^16-1=65535字节。
发送过的数据未收到确认之前必须保留,以便超时重传时使用。发送窗口没收到确认不动,收到新的确认后前移。

发送缓存用来暂时存放: 发送应用程序传送给发送方 TCP 准备发送的数据;TCP 已发送出但尚未收到确认的数据。

接收缓存用来暂时存放:按序到达的、但尚未被接收应用程序读取的数据; 不按序到达的数据

必须强调三点:

  1. A 的发送窗口并不总是和 B 的接收窗口一样大(因为有一定的时间滞后)。
  2. TCP 标准没有规定对不按序到达的数据应如何处理。通常是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程。
  3. TCP 要求接收方必须有累积确认的功能,这样可以减小传输开销(累积确认:一个确认包确认了累积到某一序号的所有包,而不是对每个序号都发确认包。)
初始化序列号ISN和确认号

第一次握手时客户端向服务器发送一个同步数据包请求建立连接,该数据包中,初始序列号(ISN)是客户端随机产生的一个值,确认号(ACK的值)是0;

客户端和服务端在建立tcp连接时,双方都会发送SYN报文并初始化序号(英文为:Initial Sequence Number,简称ISN)。序号的范围是0 ~ 231−1之间,而且序号的生成也是随机的,通常是一个很大的数值,因此可以认为每个tcp连接使用的序号也是不一样的。

随机可以避免被攻击者伪造包。接收到包的序号不在当前连接的范围内则丢弃。

猜你喜欢

转载自blog.csdn.net/tony__lin/article/details/84575767
今日推荐