TCP协议

作者: 浮萍向北 | 来源:发表于2019-11-27 00:05 被阅读0次

    TCP协议的特性

    • 顺序问题 ,稳重不乱;
    • 丢包问题,承诺靠谱;
    • 连接维护,有始有终;
    • 流量控制,把握分寸;
    • 拥塞控制,知进知退;

    TCP 包头格式

    TCP 包头格式.jpg
    包头内容如上图所示
    • 源端口号和目标端口号,数据从哪来到哪去。
    • 包的序号,解决包乱序问题
    • 确认序号,发出去的包要有回复 要不然不知道包对方有没有收到,如果没有就会重新发送,直到到达。
    • 状态位,日常分析有用的就五个字段 SYN, FIN, ACK, PSH, RST。TCP 是面向连接的 双方要维护连接的状态这些带状态的包的发送,会引起双方的状态变更。
    • 窗口大小,TCP 要做流量控制,通信双方各声明一个窗口,标识当前能够处理能力。
    状态位,日常分析有用的就五个字段
    • SYN 表示建立连接
    • FIN 表示关闭连接
    • ACK 表示响应
    • PSH 表示有DATA数据传输
    • RST 表示连接重置

    TCP 三次握手

    TCP 的建立 我们常常称为三次握手。


    TCP三次握手.png
    双端状态值变化(状态机)

    一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。然后客户端主动发起连接 SYN,之后处于 SYN-SENT 状态。服务端收到发起的连接,返回 SYN,并且 ACK 客户端的 SYN,之后处于SYN-RCVD 状态(同步空闲字符接收到状态)客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK,之后处于 ESTABLISHED (已建立)状态,因为它一发一收成功了。服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也一发一收了。

    我们也常称为“请求 -> 应答 -> 应答之应答”的三个回合。这个看起来简单,其实里面还是有很多的学问,很多的细节。为什么要三次?而不是两次?两个端一来一回不就可以了?为了可靠,为什么不四次?
    • 当A要发起一个连接,到达了B B收到了请求包,知道了A 的存在 并且知道 A要和它建立连接 于是B就发了一个连接给A 这个应答包一入网络深似海,不知道能不能到达A。这个时候B自然不能认为连接是建立好的。因为应答包仍然会丢,会绕弯路,或者 A 已经挂了都有可能。A 建立连接的时候,请求包重复发了几次,有的请求包绕了一大圈又回来了,B 会认为这也是一个正常的的请求的话,因此建立了连接,可以想象,这个连接不会进行下去,也没有个终结的时候,纯属单相思了。因而两次握手肯定不行。
    • B 发送的应答可能会发送多次,但是只要一次到达 A,A 就认为连接已经建立了,因为对于 A 来讲,他的消息有去有回。A 会给 B 发送应答之应答,而 B 也在等这个消息,才能确认连接的建立,只有等到了这个消息,对于 B 来讲,才算它的消息有去有回。当然 A 发给 B 的应答之应答也会丢,也会绕路,甚至 B 挂了。按理来说,还应该有个应答之应答之应答,这样下去就没底了。所以四次握手是可以的,四十次都可以,关键四百次也不能保证就真的可靠了。只要双方的消息都有去有回,就基本可以了。
    三次握手除了双方建立连接外,主要还是为了沟通一件事情,就是 TCP 包的序号的问题。
    • A 要告诉 B,我这面发起的包的序号起始是从哪个号开始的,B 同样也要告诉 A,B 发起的包的序号起始是从哪个号开始的。
    • 这个序号的起始序号是随着时间变化的,可以看成一个 32 位的计数器,每 4ms 加一,如果计算一下,如果到重复,需要 4 个多小时,那个绕路的包早就死翘翘了,因为我们都知道 IP 包头里面有个 TTL,也即生存时间。

    TCP 四次挥手

    TCP 四次挥手.png
    双端状态值变化(状态机)

    断开的时候,我们可以看到,当 A 说“不玩了”,就进入 FIN_WAIT_1 的状态,B 收到“A 不玩”的消息后,发送知道了,就进入 CLOSE_WAIT 的状态。
    A 收到“B 说知道了”,就进入 FIN_WAIT_2 的状态,如果这个时候 B 直接跑路,则 A 将永远在这个状态。TCP 协议里面并没有对这个状态的处理,但是 Linux 有,可以调整 tcp_fin_timeout 这个参数,设置一个超时时间。
    如果 B 没有跑路,发送了“B 也不玩了”的请求到达 A 时,A 发送“知道 B 也不玩了”的 ACK 后,从 FIN_WAIT_2 状态结束,按说 A 可以跑路了,但是最后的这个 ACK 万一 B 收不到呢?则 B 会重新发一个“B 不玩了”,这个时候 A 已经跑路了的话,B 就再也收不到 ACK 了,因而 TCP 协议要求 A 最后等待一段时间 TIME_WAIT,这个时间要足够长,长到如果 B 没收到 ACK 的话,“B 说不玩了”会重发的,A 会重新发一个 ACK 并且足够时间到达 B。
    A 直接跑路还有一个问题是,A 的端口就直接空出来了,但是 B 不知道,B 原来发过的很多包很可能还在路上,如果 A 的端口被一个新的应用占用了,这个新的应用会收到上个连接中 B 发过来的包,虽然序列号是重新生成的,但是这里要上一个双保险,防止产生混乱,因而也需要等足够长的时间,等到原来 B 发送的所有的包都死翘翘,再空出端口来。

    等待的时间设为 2MSL,MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 域,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。协议规定 MSL 为 2 分钟,实际应用中常用的是 30 秒,1 分钟和 2 分钟等。

    TCP 状态机

    TCP 状态机.jpg

    相关文章

      网友评论

          本文标题:TCP协议

          本文链接:https://www.haomeiwen.com/subject/kgjuwctx.html