马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
🔥个人主页🔥:孤寂大仙V
🌈收录专栏🌈:盘算机网络
🌹往期回顾🌹: 【盘算机网络】传输层UDP协议
🔖流水不争,争的是滔滔不息
一、TCP协议
UDP(User Datagram Protocol)是一种无毗连的传输层协议,提供简朴的不可靠数据传输服务。与TCP不同,UDP不包管数据包的顺序、可靠性或重复性,但具有低延迟和低开销的特点,适用于实时性要求高的场景。
UDP的特点
无毗连:通信前无需建立毗连,直接发送数据。
不可靠:不包管数据包的到达、顺序或重复性。
高效:头部开销小(仅8字节),无流量控制、拥塞控制机制。
支持广播和多播:可向多个目的同时发送数据。
TCP协议是面向字节省的没有边界的概念,不像UDP中还规定好的一个报文大巨细,当有多个报文的时候也能区分出每个不同的报文。所以TCP中会出现黏包的标题,即这个报文和下一个报文黏在一起,为办理这一标题可以在应用程手动添加边界。
确认应答机制
确认应答机制(ACK机制)是可靠传输协议(TCP)中的核心特征之一,用于确保数据资网络中可靠、无误的到达对方。
你发一条消息,我必须给你回个“收到”。你不回我就一直发,直到你回。
比如客户端发送一个信息给服务端,服务端必须要给客户端应答,有了服务端的应答,客户端才气确定信息被服务端吸收到了。具有应答可以包管历史消息的可靠性。TCP协议中包管可靠性,处于核心职位的就是确认应答机制。
不必要对应答做应答
二、TCP协议段格式
4位首部长度
TCP首部的长度字段是4位,表示TCP首部的长度,以4字节(32位)为单元。最大值为15,因此TCP首部最大长度为15 × 4 = 60字节。TCP报头的长度不是固定的,通过上图TCP协议段格式图,发现没有TCP长度不像UDP那样有UDP长度,所以TCP报文也不是固定的。这也是TCP粘包标题的根源,必要应用层自行处理边界标题。
序号和确认序号(确认应答机制)
发送方把一段数据放进TCP报文段,打上序号发送出去,吸收方收到数据后,反回一个确认报文,此中带上期望的下一个序号。比如收到序号100的包,数据长1字节,就返回101,表示已经收到了100到101了。收到确认序号表明制定报文之前的全部信息,已经全部收到了,下一次发送从确认序号开始。
服务器不是只做应答,做的是捎带应答(服务器应答的时候把要发送的报文加上)。所以服务器也必要对方的应答。不管是客户端照旧服务端都必要给对方发送报文报文中有序号然后得到确认序号。
16位窗口巨细
发送端发送数据,取决于吸收端吸收缓冲区剩余空间的巨细。16位窗口巨细告诉发送方在未收到确认(ACK)的情况下,可以发送的最大数据量,从而避免发送方发送过多数据导致吸收方缓冲区溢出。16位窗口巨细作为报文中的一个字段,在报文在网络中传输的时候将自己的16位窗口巨细信息给对方。
6个保留位
六个保留位是六个比特位,URG、ACK、PSH、RST、SYN、FIN、。六个保留位是标志位,本质就是报头中的比特位。注意:网络中传输的是整个报文信息,报文中有报头和有效载荷,这些字段在有效载荷中。
**计划保留位是为了让吸收方收到不同的TCP报文,针对不同报文的类型,吸收方要有不同的行为做法。
**
从这里先引入三次握手四次挥手,后面细聊
虽然好多图都这么画,但是在网络中传输的是报文,报头内里有字段是表示毗连表示应答等等。
SYN
SYN是同步标志位,建立毗连用的,握手过程使用的标志位。前两次握手,不能带数据只有报头发送给对方,三次握手没有完成就不能发送数据。这三次握手就是发送端和吸收端的协商。
ACK
确认号是否有效,表明报文是一个应答报文,ACK标志位险些常设位1。
FIN
关照对方,本端要关闭了,我们称带FIN标识的位结束报文。
PSH
要求吸收端应用步伐立刻从TCP缓冲区把数据读走。
当发送方设置PSH=1,吸收方的TCP协议栈会尽快将缓冲区中的数据(包括该报文段)推送到应用层。
RST
对方要求重新建立毗连,把携带RST标识的称为复位报文段。
举一个极端例子,发送端和客户端建立毗连进行三次握手,发送端把对服务端的应答发送完了那么发送端就以为自己就与服务端建立了毗连。服务端吸收到发送端的应答,这个过程是有时间差的,假如应答报文没有被服务端吸收到,那么服务端以为没有与发送端建立毗连。发送端与服务端毗连建立是否乐成认知不一致。这时候服务端要给发送端发送RST,让毗连重置。
其着实通信过程中毗连出现任何标题,都可以进行重置。
URG 告急指针
URG标志位是表示告急指针是否有效。URG标志位为1表示告急指针见效。
告急指针的工作过程:tcp传输比如说在吸收端缓冲区,吸收到的数据是按字节省式的吸收队列,可以明白为报文在缓冲区中是有序排列的。假如有数据想被优先读取优先处理就要用到告急指针,比方吸收端缓冲区的数据中,用户想终止这些数据的传输,末了传进来的报文在队列的末了,这个报文也就终止的告急数据,告急指针就会开始运作了。
告急指针这种行为不是主流。
三、超时重传明白丢包
发送端给吸收端发送数据,假如没有得到应答,数据就一定丢了吗?分为两种情况,一种主机A向主机B发送报文确实丢包了主机B没有收到报文,另一种主机A向主机B发送报文主机B收到了主机A的报文,但是应答报文丢失了。无法百分百包管对方是否收到信息,就无法包管可靠性。
**为了应对上述无法百分百包管对方是否收到信息的情况,发送端假如特定的时间间隔内没有收到接受端的应答,就会触发超时重传,重新给吸收端发送报文。**有一种情况假如发送端给吸收端重传了报文信息,但是吸收端也吸收到了之前第一次的报文信息,这是会出现报文重复的标题吗?不会,因为吸收端会根据序号进行去重。
这个特定的时间间隔是多少呢?
最理想的情况下,找到一个最小的时间,确保确认应答一定能在这个时间内返回。但是这个时间的长短,随着网络情况的不同,是有差别的。假如超时时间设的太长,会影响整体的重传效率,假如超时时间设的太短,有大概会频仍发送重复的包。
TCP 为了包管无论在任何情况下都能比力高性能的通信, 因此会动态盘算这个最大超
时时间。Linux 中(BSD Unix 和 Windows 也是云云), 超时以 500ms 为一个单元进行控
制, 每次判断超时重发的超时时间都是 500ms 的整数倍,假如重发一次之后, 仍然得不到应答, 等待 2500ms 后再进行重传,假如仍然得不到应答, 等待 4500ms 进行重传. 依次类推, 以指数情势递增,累计到一定的重传次数, TCP 以为网络或者对端主机出现异常, 逼迫关闭毗连。
四、三次握手四次挥手
客户端和服务端建立的毗连,也是要通过先描述再构造管理起来的。进行管理的也是一个布局体struct_link,布局体中包含毗连的信息。所以建立毗连是有成本的,时间成本和空间成本。一个台主机操作体系建立大量的毗连就会变卡,甚至开始杀建立好的毗连进程。
之前写TCP通信的代码,客户端必要写connect去毗连服务器,三次握手也是connect发起的。connect发起后,建立毗连的过程由客户端和服务端的操作体系自动完成。注意accept不参加三次握手,写代码的时候我们也发现,accept创建的套接字是用来干活的,connect才是用来建立毗连的。connect() 是三次握手的出发点,客户端通过它向服务端发起 SYN 报文。三次握手完成之后,服务端的 accept() 才返回一个新的 socket 文件描述符,这个 socket 就是用来“干活”的。所以我们在代码里看到:服务端 listen 的 socket 是用来“等人”的,accept() 拿到的 socket 是用来和客户端通信的。
为什么三次握手?
外部条件:以最短的方式,进行验证发送端和服务端是全双工的,本质是两个所处的网络是畅通的的能支持全双工。
通信双方:百分百确认双方通信意愿。
三次握手,原来就是通信双方想要进行通信才建立链接的。所以在第二次握手的时候,连SYN和ACK一起发出去了,这就是捎带应答。
为什么四次握手不进行捎带应答
因为断开毗连时,双方不是"同时想断",而是一方先想断开的。
客户端说:我要断了(FIN),服务端说:好,我知道了(ACK),但我还有话没说完,等我说完再断。服务端说:好了,我也说完了(FIN)。客户端说:收到,咱们彻底断了(ACK)。
四次挥手不能捎带的本质原因是:服务端不能立即发FIN,它大概还有数据没发完,得等缓冲区清空后再说,所以不能捎带两个动作,只能形成四次挥手。
状态
CLOSE_WAIT
如图假如客户端与服务端之前是建立毗连的,如今客户端断掉毗连,但是服务端没有断掉毗连,服务端就处于CLOSE_WAIT的状态,服务端依旧占用文件描述符,毗连没有开释。此时服务端可以给客户端发消息。与上述四次挥手为什么不进行捎带应答对应。
TIME_WAIT
自动断开毗连的一方会进入TIME_WAIT状态,纵然四次握手已经完成(就是如上图客户端以为自己发送了ACK就完成四次挥手了)。发送完末了一个 ACK 后,才进入 TIME_WAIT 状态,并开始等待 2MSL(最大报文段生存时间)。等待2MSL让两个传输方向上尚未被吸收到的或迟到的报文消散。
假设一个极端情况——客户端发送了数据包后立刻关闭毗连,结果数据包因为网络拥堵延迟漂在半路。此时客户端又快速重启,并复用了原来的端口号。假如没有 TIME_WAIT,谁人“幽灵数据包”一旦抵达服务器,大概会被误以为是新的毗连数据,导致数据混乱甚至安全标题。
所以为什么要等 2MSL?
确保对方收到了刚才你发的谁人末了的 ACK。假如对方充公到,会重发 FIN;那你还在 TIME_WAIT 状态中,可以再发一次 ACK。
同时避免旧毗连残留的数据影响之后新建立的毗连。
我们发现我们的代码毗连服务器用的端口号,用完一次短时间内不能复用。 TCP 的 TIME_WAIT 状态限定了端口的短时间复用,就是为了包管毗连的安全性和协议的严谨性,不是你断了毗连马上就能拿这个端口再用一遍的。照旧上述谁人极端情况,重新建立毗连后,因为绑定了新的端口号,源端口和目的端口匹配不上,"幽灵数据包👻"就自动抛弃了。
五、滑动窗口
滑动窗口是 TCP 协议中实现“流量控制”和“可靠传输”的核心机制之一。可以把它想成一个动态变化的“可发送/可吸收数据范围”,帮助发送方和吸收方协调通信节奏,防止“你发我收不过来”的情况。发送方向对方发送多少数据是由滑动窗口决定的。
滑动窗口就是一个数组,由两个指针维护,就像算法中的谁人滑动窗口一下。已经发送的谁人区域,就是这部分空间的数据已经被使用了这部分数据已经无效了,不必要刻意清空缓冲区,前面聊过序号随着发送序号会依次增大,滑动窗口未来是向右滑动的。
滑动窗口的巨细=对方的吸收本领。发送方滑动窗口,维护滑动窗口的start相当于是对方的确认序号,end相当于start+对方的整个窗口巨细。**注意:吸收方也有滑动窗口!这个窗口是 整个吸收缓冲区中还没有被填满的那一部分,每次吸收到新的数据并交付给上层应用,缓冲区就开释了,窗口也就向前滑动。**滑动窗口不是整个缓冲区,而是“缓冲区中还空着”的部分。
滑动窗口的本质是流量控制的具体实现方案。
发送方的滑动窗口肯定不能向左滑动。滑动窗口是可以变大、变小或者稳定的,因为滑动窗口的巨细=对方的吸收本领,假如吸收方缓冲区内的未向上交付的数据太多,这些数据都在缓冲区中,那么吸收方的滑动窗口就变小了,发送方的滑动窗口相对应肯定也就会变小。假如吸收方缓冲区内数据没有堆积,那么吸收方的滑动窗口就变大了,发送方的滑动窗口相对应也就会变大。稳定就是比力稳定的情况。
假如滑动窗口交付数据丢包怎么办?
这里把滑动窗口报完丢失归为三类,最左侧报文丢失、中间报文丢失、最右侧报文丢失。
最左侧报文丢失,分为最左侧报文对应的应答丢失了和最左侧报文真的丢失了。
这种情况下, 部分 ACK 丢了并不要紧, 因为可以通过后续的 ACK 进行确认。确认序号表示这个确认序号之前的报文全都收到了。也就是说,假如1-1000的确认序号应该是1001但是没有收到,下一个10001-2000的确认序号2001收到了,根据确认序号表示确认序号之前的报文全部收到了,就可以确认2001之前的报文全部收到了。这样发送方就可以确认1-1000的报文没有丢。
假如报文真丢了,发送端会一直收到 1001 这样的 ACK, 就像是在提醒发送端 “我想要的是 1001” 一样。假如发送端主机一连三次收到了同样一个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送。这个时候吸收端收到了 1001 之后, 再次返回的 ACK 就是 7001 了(因为 2001 -7000)吸收端其实之前就已经收到了, 被放到了吸收端操作体系内核的吸收缓冲区中。这个机制叫做快重传。
上面说的是最左侧报文丢失,其实中间报文丢失和最右侧报文丢失,都会转化为最左侧报文丢失。因为假如是中间报文丢失,左边没有丢失的话,左边就正常发送报文,相当于滑动窗口的start指向了中间报文的开头,中间报文就成了最左侧报文。
滑动窗口不会跳过报文进行应答,确认序号定义决定,确认消息一定要一连确认,所以要一连发送。所以滑动窗口发报文肯定是一连的,不能跳跃。由于 TCP 使用累计确认机制,滑动窗口内的数据必须按序一连发送与确认,不能跳跃发送或跳跃确认,否则窗口无法前移。
滑动窗口总是向右滑动,不会“向左滑”或“跳跃确认”。虽然序号值是有限的(32 位),但当到达最大值后会回绕,从 0 重新开始,因此可以将整个序号空间明白为一个环形布局,滑动窗口在此中不断推进。
快重传 vs 超时重传
要想进行快重传得满足一个条件,收到三个同样的确认应答时则进行重发。超时重传上面聊过,纵然一个报文在一段时间间隔内没有收到应答,会进行重传。在这里超时重传更像是快重传的一种兜底计谋。
六、流量控制
吸收端处理数据的速率是有限的. 假如发送端发的太快, 导致吸收端的缓冲区被打满, 这个时候假如发送端继承发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应。
因此 TCP 支持根据吸收端的处理本领, 来决定发送端的发送速率. 这个机制就叫做流量控制。
吸收端将自己可以吸收的缓冲区巨细放入 TCP 首部中的 “窗口巨细” 字段, 通过 ACK 端关照发送端。
窗口巨细字段越大, 说明网络的吞吐量越高。
吸收端一旦发现自己的缓冲区快满了, 就会将窗口巨细设置成1一个更小的值关照给发送端;
发送端接受到这个窗口之后, 就会减慢自己的发送速率。
假如吸收端缓冲区满了, 就会将窗口置为 0; 这时发送方不再发送数据, 但是必要定期发送一个窗口探测数据段, 使吸收端把窗口巨细告诉发送端。
吸收端把窗口巨细告诉发送端,CP 首部中, 有一个 16 位窗口字段就是存放了窗口巨细信息。16 位数字最大表示 65535, 那么 TCP 窗口最大就是 65535 字节么?实际上, TCP 首部 40 字节选项中还包含了一个窗口扩大因子 M, 实际窗口巨细是 窗口
字段的值左移 M 位。
七、拥塞控制
网络通讯中不只和发送方和吸收方有关,也必要考虑网络的标题。TCP不仅仅考虑了双方主机的标题,还考虑了网络本身的标题。当网络大面积丢包,发送方判断出现了网路拥塞的标题。网络拥塞不能明白重发,全部发送方都立即重发不就成了堵上加堵了吗。这里要明白在网络通信中,有许多发送端主机和许多吸收端主机,都必要通过这一个网络进行通信。
当网络拥塞时,这一个网络下的,多个发送端的多个主机都接纳拥塞控制这种计谋。TCP 引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速率传输数据。
**拥塞窗口是一个临界值,值以内网络大概率不拥塞,值以上,网络大概拥塞。**拥塞窗口是在盘算机内衡量网络是否会拥堵的一个指标。网络好坏是会变化的,所以也就决定了拥塞窗口也一定到进行更新变化。
发送方的滑动窗口其实不但单是由对端滑动窗口巨细决定的,拥塞窗口和对方滑动窗口谁小谁是发送端的滑动窗口巨细。发送开始的时候, 定义拥塞窗口巨细为 1。每次收到一个 ACK 应答, 拥塞窗口加 1。每次发送数据包的时候, 将拥塞窗口和吸收端主机反馈的窗口巨细做比力, 取较小的值作为实际发送的窗口。
慢启动开始,如上图拥塞窗口增速非常快,指数级增长,但是不是一直指数级增长的。为了尽快恢复网络通信所以一开始要快一点,办理拥塞标题(网络拥塞就是网络中报文太多造成堵塞,所以一开始当前网络全部发送方发送报文渐渐发送)。等到线性增长的阶段,本质是探测网络的拥塞窗口的值。
慢启动开始,拥塞窗口指数级增长,到达一定阈值就会开始线性增长。拥塞窗口在增加,发送的数据量不一定是在增加的,上面也说过每次发送数据包的时候, 将拥塞窗口和吸收端主机反馈的窗口巨细做比力, 取较小的值作为实际发送的窗口,所以是不一定的。线性增长到一定程度,这时候网络又开始堵了,又重新从1开始慢启动,但是这次慢启动到线性增长的阈值是上一次网络拥塞窗口巨细的一半。
拥塞控制, 归根结底是 TCP 协议想尽大概快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案
八、延迟应答
假如吸收数据的主机立刻返回 ACK 应答, 这时候返回的窗口大概比力小。
假设吸收端缓冲区为 1M, 一次收到了 500K 的数据;。假如立刻应答, 返回的窗口就是 500K。但实际上大概处理端处理的速率很快, 10ms 之内就把 500K 数据从缓冲区消费掉了。在这种情况下, 吸收端处理还远没有到达自己的极限, 纵然窗口再放大一些, 也能处理过来。假如吸收端稍微等一会再应答, 比如等待 200ms 再应答, 那么这个时候返回窗口巨细就是 1M。
一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目的是在包管网络不拥塞的情况下只管进步传输效率。
九、捎带应答
“捎带应答”(piggybacking)是网络通信中的一个术语,通常出如今面向毗连的协议(如TCP)中,指的是在发送确认(ACK)报文的同时,顺便携带要发送的数据,从而进步通信效率。
十、TCP异常
进程终止: 进程终止会开释文件描述符, 仍然可以发送 FIN和正常关闭没有什么区别。
呆板重启: 和进程终止的情况相同。
呆板掉电/网线断开: 吸收端以为毗连还在, 一旦吸收端有写入操作, 吸收端发现毗连已经不在了, 就会进行 reset. 纵然没有写入操作, TCP 自己也内置了一个保活定时器, 会定期询问对方是否还在. 假如对方不在, 也会把毗连开释。
另外, 应用层的某些协议, 也有一些这样的检测机制. 比方 HTTP 长毗连中, 也会定期检测对方的状态. 比方 QQ, 在 QQ 断线之后, 也会定期实验重新毗连。
|