你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

一文让你读懂TCP协议

[复制链接]
gaosmile 发布时间:2020-10-5 19:37
微信图片_20201005193312.jpg

) ^& c" \8 J# g( d. _) e

7 B2 A, q; U/ m2 m
TCP 是互联网核心协议之一,本文介绍它的基础知识。
' ~5 a/ |2 s: E# I+ _4 C  Z
微信图片_20201005193316.png
一、TCP 协议的作用互联网由一整套协议构成。TCP 只是其中的一层,有着自己的分工。 微信图片_20201005193320.png 7 M) G- `& s5 d0 [
(图片说明:TCP 是以太网协议和 IP 协议的上层协议,也是应用层协议的下层协议。)6 d$ o- u. \/ P% D5 A2 d
最底层的以太网协议(Ethernet)规定了电子信号如何组成数据包(packet),解决了子网内部的点对点通信。 微信图片_20201005193323.jpg " H& h$ ~% j0 Q- P. f( a1 d3 r  I
(图片说明:以太网协议解决了局域网的点对点通信。)
) c$ L9 b$ ^0 V' |但是,以太网协议不能解决多个局域网如何互通,这由 IP 协议解决。* f6 F" n8 m& _
微信图片_20201005193326.jpg
) j: U% o* `  S1 N2 x(图片说明:IP 协议可以连接多个局域网。)
3 Y( q0 y' Z0 @9 O9 ?  d0 _IP 协议定义了一套自己的地址规则,称为 IP 地址。它实现了路由功能,允许某个局域网的 A 主机,向另一个局域网的 B 主机发送消息。/ t' C8 ~. i2 y. h- Y* i9 O
微信图片_20201005193330.jpg ' r0 ^5 d  n( g- z( Y- v9 t0 A
(图片说明:路由器就是基于 IP 协议。局域网之间要靠路由器连接。)/ \! J. l4 A% |* e" ~' Q0 ]$ Y
路由的原理很简单。市场上所有的路由器,背后都有很多网口,要接入多根网线。路由器内部有一张路由表,规定了 A 段 IP 地址走出口一,B 段地址走出口二,......通过这套"指路牌",实现了数据包的转发。6 n) {/ D$ K+ J+ F, V
微信图片_20201005193334.jpg
0 I$ o: ^  w/ K; Y, ?0 K(图片说明:本机的路由表注明了不同 IP 目的地的数据包,要发送到哪一个网口(interface)。)- a  U5 [( ~. L- [7 t
IP 协议只是一个地址协议,并不保证数据包的完整。如果路由器丢包(比如缓存满了,新进来的数据包就会丢失),就需要发现丢了哪一个包,以及如何重新发送这个包。这就要依靠 TCP 协议。
* r7 A" ~3 Q) o9 u, h简单说,TCP 协议的作用是,保证数据通信的完整性和可靠性,防止丢包# \6 z+ a- g# ^- A+ ^' ?& ~1 `
9 l5 y$ ?) c& G1 T
6 `& m; S) J7 \' C: s! l7 ?
二、TCP 数据包的大小
" P1 u! d9 r; h, F) z以太网数据包(packet)的大小是固定的,最初是1518字节,后来增加到1522字节。其中, 1500 字节是负载(payload),22字节是头信息(head)。
# @  u. n* P# n0 m: ]4 [( gIP 数据包在以太网数据包的负载里面,它也有自己的头信息,最少需要20字节,所以 IP 数据包的负载最多为1480字节。 微信图片_20201005193339.png * S' v3 _) x! z8 \4 X. N4 h1 H
(图片说明:IP 数据包在以太网数据包里面,TCP 数据包在 IP 数据包里面。)9 T) I# @0 [" y# p" o, k; u
TCP 数据包在 IP 数据包的负载里面。它的头信息最少也需要20字节,因此 TCP 数据包的最大负载是 1480 - 20 = 1460 字节。由于 IP 和 TCP 协议往往有额外的头信息,所以 TCP 负载实际为1400字节左右。! O0 E( z/ r1 m
因此,一条1500字节的信息需要两个 TCP 数据包。HTTP/2 协议的一大改进, 就是压缩 HTTP 协议的头信息,使得一个 HTTP 请求可以放在一个 TCP 数据包里面,而不是分成多个,这样就提高了速度。" `8 `+ P. ^8 V! q- _; v
微信图片_20201005193343.png ! v$ }' q# K0 v; X) A5 Q4 A2 H
(图片说明:以太网数据包的负载是1500字节,TCP 数据包的负载在1400字节左右。)
3 _2 Y+ D6 h# P; T) f$ z% c5 n9 h- ]6 [, ?. i6 @  Z2 b
) [, z% R0 o+ h. k* Q* e# E
三、TCP 数据包的编号(SEQ). D" p5 t# |$ m# Y0 c
一个包1400字节,那么一次性发送大量数据,就必须分成多个包。比如,一个 10MB 的文件,需要发送7100多个包。
- V4 f$ s  L* Q0 v8 @4 l发送的时候,TCP 协议为每个包编号(sequence number,简称 SEQ),以便接收的一方按照顺序还原。万一发生丢包,也可以知道丢失的是哪一个包。
  C5 a! c- Q; D) Y第一个包的编号是一个随机数。为了便于理解,这里就把它称为1号包。假定这个包的负载长度是100字节,那么可以推算出下一个包的编号应该是101。这就是说,每个数据包都可以得到两个编号:自身的编号,以及下一个包的编号。接收方由此知道,应该按照什么顺序将它们还原成原始文件。
% S0 Z  u) ?  ?. k- ~8 F 微信图片_20201005193346.png   T0 x: E( r7 Y6 Y5 W( ~
(图片说明:当前包的编号是45943,下一个数据包的编号是46183,由此可知,这个包的负载是240字节。)* \7 H, P: u3 N! r  t# A: O7 @- W
* K' [/ E1 U3 X5 o3 x
7 E+ N7 Y* G2 k9 V
四、TCP 数据包的组装
" _7 z+ [9 J1 h0 q收到 TCP 数据包以后,组装还原是操作系统完成的。应用程序不会直接处理 TCP 数据包。& x- y9 T4 i# @+ Q0 u, [9 a7 y! `" W
对于应用程序来说,不用关心数据通信的细节。除非线路异常,收到的总是完整的数据。应用程序需要的数据放在 TCP 数据包里面,有自己的格式(比如 HTTP 协议)。
' S* n! z7 h) @" ]1 UTCP 并没有提供任何机制,表示原始文件的大小,这由应用层的协议来规定。比如,HTTP 协议就有一个头信息Content-Length,表示信息体的大小。对于操作系统来说,就是持续地接收 TCP 数据包,将它们按照顺序组装好,一个包都不少。/ q9 j- q; Z3 }* M
操作系统不会去处理 TCP 数据包里面的数据。一旦组装好 TCP 数据包,就把它们转交给应用程序。TCP 数据包里面有一个端口(port)参数,就是用来指定转交给监听该端口的应用程序。; z) A5 ?8 G' o  ]# a2 T; Z
微信图片_20201005193351.jpg * F3 R1 j0 {% h$ U/ d
(图片说明:系统根据 TCP 数据包里面的端口,将组装好的数据转交给相应的应用程序。上图中,21端口是 FTP 服务器,25端口是 SMTP 服务,80端口是 Web 服务器。)
: Z) x9 N3 Y0 s3 M9 y  ]) S应用程序收到组装好的原始数据,以浏览器为例,就会根据 HTTP 协议的Content-Length字段正确读出一段段的数据。这也意味着,一次 TCP 通信可以包括多个 HTTP 通信。# I! b' D. c( X; P: F
, [" u; S2 o/ ^, R2 V2 p
) J* i% I+ n" F3 i+ j6 C6 l+ p
五、慢启动和 ACK! `  s3 l% ]# k$ ]4 H
服务器发送数据包,当然越快越好,最好一次性全发出去。但是,发得太快,就有可能丢包。带宽小、路由器过热、缓存溢出等许多因素都会导致丢包。线路不好的话,发得越快,丢得越多。
; J* L8 l3 e5 ]" G- J  d最理想的状态是,在线路允许的情况下,达到最高速率。但是我们怎么知道,对方线路的理想速率是多少呢?答案就是慢慢试。
) v' ~2 \$ I0 I; CTCP 协议为了做到效率与可靠性的统一,设计了一个慢启动(slow start)机制。开始的时候,发送得较慢,然后根据丢包的情况,调整速率:如果不丢包,就加快发送速度;如果丢包,就降低发送速度。: H9 a/ `6 d% R& }0 q
Linux 内核里面设定了(常量TCP_INIT_CWND),刚开始通信的时候,发送方一次性发送10个数据包,即"发送窗口"的大小为10。然后停下来,等待接收方的确认,再继续发送。
5 }  t: |" R5 A! ~% {9 I$ ~+ T默认情况下,接收方每收到两个 TCP 数据包,就要发送一个确认消息。"确认"的英语是 acknowledgement,所以这个确认消息就简称 ACK。3 x/ c1 X# o1 v& I/ V+ p: P% [
ACK 携带两个信息。
期待要收到下一个数据包的编号
' S3 }/ w* H1 ^接收方的接收窗口的剩余容量
6 {& W, g! C( E8 b0 o! z
发送方有了这两个信息,再加上自己已经发出的数据包的最新编号,就会推测出接收方大概的接收速度,从而降低或增加发送速率。这被称为"发送窗口",这个窗口的大小是可变的。
9 l& g+ ?. ^$ _! @( _5 V( R 微信图片_20201005193355.png
" E3 V2 A6 `4 r& B: {6 j" s- v(图片说明:每个 ACK 都带有下一个数据包的编号,以及接收窗口的剩余容量。双方都会发送 ACK。), b& D7 y- ?1 \6 N9 `+ L
注意,由于 TCP 通信是双向的,所以双方都需要发送 ACK。两方的窗口大小,很可能是不一样的。而且 ACK 只是很简单的几个字段,通常与数据合并在一个数据包里面发送。
; E5 y' R" I- L% [! J. h 微信图片_20201005193400.jpg
! I; m6 P8 L) j, Q% a6 c: K(图片说明:上图一共4次通信。第一次通信,A 主机发给B 主机的数据包编号是1,长度是100字节,因此第二次通信 B 主机的 ACK 编号是 1 + 100 = 101,第三次通信 A 主机的数据包编号也是 101。同理,第二次通信 B 主机发给 A 主机的数据包编号是1,长度是200字节,因此第三次通信 A 主机的 ACK 是201,第四次通信 B 主机的数据包编号也是201。)
( ^, Y8 @3 o) b' _& x& ~即使对于带宽很大、线路很好的连接,TCP 也总是从10个数据包开始慢慢试,过了一段时间以后,才达到最高的传输速率。这就是 TCP 的慢启动。5 ?2 t5 W7 b" {( O! A- u: j, W
  d7 M' j0 D0 s

# i( H8 W3 {* u% U+ v+ i! U8 _. x, `六、数据包的遗失处理
2 ^9 [& o1 e/ JTCP 协议可以保证数据通信的完整性,这是怎么做到的?& v: H: L. A, ~, H  W: `8 C! Q
前面说过,每一个数据包都带有下一个数据包的编号。如果下一个数据包没有收到,那么 ACK 的编号就不会发生变化。
" U; B/ e$ G6 Z. P举例来说,现在收到了4号包,但是没有收到5号包。ACK 就会记录,期待收到5号包。过了一段时间,5号包收到了,那么下一轮 ACK 会更新编号。如果5号包还是没收到,但是收到了6号包或7号包,那么 ACK 里面的编号不会变化,总是显示5号包。这会导致大量重复内容的 ACK。5 l  R1 P& ?9 W
如果发送方发现收到三个连续的重复 ACK,或者超时了还没有收到任何 ACK,就会确认丢包,即5号包遗失了,从而再次发送这个包。通过这种机制,TCP 保证了不会有数据包丢失。0 Q+ x. D) h- `8 u8 A; j9 ?

; o* O4 c! F9 H, _2 t(图片说明:Host B 没有收到100号数据包,会连续发出相同的 ACK,触发 Host A 重发100号数据包。): o8 s1 K4 e2 Z, j5 E

! E6 A; L  R! P' }5 i1 g
9 v: a' K) e- R) P* o8 F9 P
微信图片_20201005193403.png
赞 收藏 评论0 发布时间:2020-10-5 19:37

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版