你可能不知道的传输层协议具体细节2-图文详解

我们上文讲到数据包的结构,ip数据包带着tcp包走电线,一路火花带闪电的情况。那为啥要让ip包带着tcp包走呢,这是我们下次一定要讲的 网络层的内容,这期先把传输层协议说完先


协议肯定得要“三连”对吧,那么那些制定者留下了哪些重要的信息作为参考呢:

tcp头字段

seq 序号 32位标识数据段在已发送的数据流中的位置
ack 确认号,验证是否已被接收
SYN 为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步
ACK 为1表示确认号字段有效
FIN 为1表示发送方没有数据要传输了,要求释放连接。
PSH 指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满
RST 为1表示出现严重差错。可能需要重现创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求

序号seq

TCP会话的每一端都包含一个32位(bit)的序列号,该序列号被用来跟踪该端发送的数据量。每一个包中都包含序列号,在接收端则通过确认号用来通知发送端数据成功接收

当某个主机开启一个TCP会话时,他的初始序列号是随机的,可能是0和4,294,967,295(二的32次方-1)之间的任意值---------tcp/ip详解协议卷第18章18.2.3解释初始序列号随时间变化,每个连接有不同的初始序列号,每4ms加一


在 TCP 数据报中,有一个 序列号 (Sequence Number)。如果序列号被人猜出来,就会展现出 TCP 的脆弱性。

如果选择合适的序列号、IP地址以及端口号,那么任何人都能伪造出一个 TCP 报文段,从而 打断 TCP 的正常连接[RFC5961]。一种抵御上述行为的方法是使初始序列号(或者临时端口 号[RFC6056])变得相对难以被猜出,而另一种方法则是加密。

Linux 系统采用一个相对复杂的过程来选择它的初始序列号。它采用基于时钟的方案,并且针对每一个连接为时钟设置随机的偏移量。随机偏移量是在连接标识(由 2 个 IP 地址与 2 个端口号构成的 4 元组,即 4 元组)的基础上利用加密散列函数得到的。散列函数的输人每隔 5 分钟就会改变一次。在 32 位的初始序列号中,最高的 8 位是一个保密的序列号,而剩余的备位则由散列函数生成。上述方法所生成的序列号很难被猜出,但依然会随着时间而逐步增加。据报告显示, Windows 系统使用了一种基于 RC4[S94] 的类似方案。

确认号ack

  1. 发送数据: 服务器向客户端发送一个带有数据的数据包。该数据包中的序列号和确认号与建立连接的第三步的数据包的序列号和确认号相同

  2. 确认收到: 客户端收到该数据包,向服务器发送一个确认数据包。该数据包中,序列号是为上一个数据包中的确认号值

    这个确认号为服务器发送的上一个数据包中的序列号+该数据包中所带的数据的大小

    回复确认收到的ack = 收到了序列号 + 数据的大小(同时也表示下一次期望收到的序号)

  • 主机A接收主机b 假设编号为0-535的字节(意味着mss值为535byte),主机A会在发往主机B的报文段的确认号字段ack上填上536

  • 每一个包都可以得到seq和ack, 接收方就可以根据编号进行排序(按照什么顺序进行还原原始文件)或者丢弃。发送方根据ack判断接收方是否收到了指定包,判断是否需要重传

    ------------------这样就保证了数据通信的完整性和可靠性,防止丢包

三次握手

  1. 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三次握手的一部分。客户端把这段连接的序号设定为32位的随机数A
  2. 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK的确认码应为A+1,SYN/ACK包本身又有一个随机产生的序号B
  3. 最后,客户端再发送一个[ACK]。此时包的Seq被设定为A+1,而ACK的确认码则为B+1(第二次握手,服务端返回的Next seq)。当服务端收到这个ACK的时候,就完成了三次握手,并进入了连接创建状态。
  4. 这里的+1是根据发送的length来决定的

snipaste_startConnect.png

第一次握手

发送方设置syn = 1, 随机seq

TCP Options

  • Maximum segment size: 65475 -- MSS : 最大片段大小
  • Window scale: 8 (multiply by 256) -- WS: “ TCP窗口比例”选项是一个选项,用于增加“传输控制协议”中允许的接收窗口大小,使其超过其以前的最大值65535字节
  • window size value: 65535 --Win
  • SACK permitted
    • That's the "Sack-Permitted" option from RFC 2018, "TCP Selective Acknowledgment Options". It says that the two machines can use "selective acknowledgment", meaning that, instead of just saying "I got all bytes up to this sequence number", they can say "I got all the bytes in this range and all the bytes in this other range", with the implication being that bytes in ranges not listed were not received, so that they can say that they got bytes before and after some ranges, but not the bytes in the middle of the range.

...

1600271255259.png

1600271300193.png

第二次握手

随机seq ack = transfer seq + 1 1600271441785.png

第三次握手

seq = transfer ack ack = 第二次的seq 1600271468100.png

通过三次握手之后,建立 HTTP连接通道

-----------上面的 tcp segment len 都为0 1600271749837.png

1600271665014.png

数据传输

客户端发送的seq和ack必须和第三次确定的seq和ack保持一致

客户端确认收到:seq = 服务端的ack ack = 服务端的seq+该数据包中所带数据的大小(同时也表示下一次期望收到的序号)

服务器回应:seq = 客户端回传的ack ack = 客户端回传的seq+客户端回传的length

服务器开始在通道里传送数据

1600272018881.png

客户端接收 http 数据

1600272340194.png

1600272419339.png

接收http 200之后,需要传递给服务器

1600272907328.png

失败的情况

如果客户端并没有接收到想要的信息,会再发一次tcp 请求

如果服务端已经完成 tcp连接,进入下一步

关闭连接

服务端关闭请求

1600273605916.png

客户端回复tcp

1600273696962.png

在这个过程中连接的每一侧都独立地被终止。当一个端点要停止它这一侧的连接,就向对侧发送FIN,对侧回复ACK表示确认

snipaste_stopConnect.png

数据包的分割

那么一次性发送大量数据,就必须分成多个包。 比如,一个 100000字节大小的文件/MSS最大报文长度 = 单个TCP报文段 这里需要注意的是,这个MSS最大报文长度每个系统都会自定义,这里带出滑动窗口的概念,考虑篇幅原因,这里就不展开细说了,有兴趣的小伙伴自行查阅文档哈

总述

snipaste_summanry.png

1600309272878.png


TCP/IP 协议用没有中间商赚差价,卖家多挣钱,买家少花钱的套路赢得大批服务商的青睐,成为互联网现象级别的协议, 让我们恭喜 TCP/IP!

猜你喜欢

转载自juejin.im/post/7035607406184759303