传输层--UDP和TCP详解

传输层:负责数据能够从发送端传输接收端。

端口号:用来标识特定服务的(某种意义上特定服务与端口号可互相甄别)

端口号(Port)标识了一个主机上进行通信的不同的应用程序;

在这里插入图片描述

1.端口号与应用层绑定,但与传输层也有一定的关系;

2.通常情况下一个端口号不能被多个服务器共同使用,但在多线程情况下可以。一个进程可以绑定多个端口号。

TCP协议(点对点传输:只知道起点和终点,不考虑中间过程,实现此过程需直到源IP地址源端口及目的IP目的端口)

在TCP/IP协议duan’kou’ho中,用“源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号”这样的五元组来标识;

端口号划分(端口号范围0-65535)

0-1023:均为知名端口号:若自行想绑定这个范围内的端口号需要管理员权限;

1024-65535:用户可随意使用,操作系统动态分配的端口号,客户端程序的端口号。(端口号是用两个字节的变量来保存)(65535为两个字节的最大值)

ssh服务器:使用22端口

ftp服务器:21端口号

telent服务器:23端口

http服务器:80端口

https服务器:443端口

执行下面命令,可看到知名端口号,我们自行写的程序需要使用端口时,要避开这些知名端口号。

cat /etc/services

怎么查看网络连接?(面试)–netstat(用来查看网络状态的重要工具)

语法:netstat[选项]

功能:查看网络状态

常用选项:

1.n拒绝显示别名,能显示数字的全部转化为数字

2.l仅列出有在Listen(监听)的服务状态

3.p显示建立相关连接的程序名

4.t(tcp)仅显示tcp相关选项

5.u(udp)仅显示udp相关选项

6.a(all)显示所有选项,默认不显示LISTEN相关

查看本机IP地址命令行为:ifconfig

查看UDP和TCP命令行:netstat -u(UDP) netstat -t(TCP) netstat -au(所有UDP) netstat -at(所有TDP)

​ netstat -aut(所有UDP和TDP的信息(源IP端口号和目的IP端口号)以名称形式显示)

​ netstat -autn(将所有UDP和TDP的信息(源IP端口号和目的IP端口号)以数字形式显示)

pidof:查看服务器进程ID

语法:pidof[进程名]

功能:通过进程名,查看进程ID

UDP协议

UDP特点:无连接、不可靠、面向数据报

在这里插入图片描述

16位的源端口号表示数据从哪里来;16位的目的端口号表明数据要到哪里去;16位UDP长度包含8字节的报头及相减剩余的均为有效载荷;16位UDP检验和是指对数据信息进行检验,上层接收到的信息可以不完整(因UDP定长故传输信息过长时会导致信息丢失)但是不能错。

1.UDP如何将报头与有效载荷分离?

因UDP报头长度固定为8个字节,接收到UDP报文时只需要将前8个字节去掉,剩余的就为有效载荷,因UDP长度为16位,故有效载荷长度也知道。

2.UDP报文如何知道将有效载荷要交给上层哪个具体协议呢?

此时我们可根据16位的目的端口号(端口号与应用层绑定,绑定目的是让UDP与TCP通过一定的方式将数据交给上层某个具体协议,目的端口号用来表明数据如何交付的问题)知道。

标长8字节和16位UDP长度两个字段合起来表明报头和有效载荷分离的问题。

如何将报头与有效载荷分离的两种方法:

1.HTTP使用空行分离报头与有效载荷;

2.UDP定长报头。

UDP特点

1.无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接;

2.不可靠:没有确认机制,没有重传机制,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息;(不可靠缺点为可能会丢包,但优点为简单快速(因若想保证可靠性就需要在报头内规定更复杂的协议,这样的话就会比正常的报头更复杂))

3.面向数据报:不能灵活地控制读写数据的次数和数量(即怎么传输就怎么接受)。

UDP缓冲区

1.UDP没有发送缓冲区,调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作;

2.UDP具有接收缓冲区,但是这个缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃。

UDP的socket既能同时读也能同时写,这个概念叫做全双工。

全双工:双方可直接同时通信。

UDP使用注意事项

UDP协议首部中有一个16位的最大长度,也就是说UDP能传输的数据最大长度时64K(2^16)(包含UDP首部)然而64K在当今的互联网环境下,是一个非常小的数字(但因UDP长度定长无法增大),如果我们需要传输的数据超过64K,就需要在应用层手动的分包,多次发送,并在接收端手动拼装。

基于UDP的应用层协议

1.NFS:网络文件系统

2.TFTP:简单文件传输协议

3.DHCP:动态主机配置协议(采用UDP协议)

4.BOOTP:启动协议(用于无盘设备启动)

5.DNS:域名解析协议(采用UDP协议)

当然也包括自己写UDP程序时自定义的应用层协议。

TCP协议(传输控制协议–面向连接):作用是对数据的传输进行一个详细的控制

TCP特点:可靠性、性能、策略(流量控制、拥塞避免、滑动窗口)

TCP本质是面向字节流。

第一件事是建立连接。

TCP协议强调对等,通信双方角色地位平等。客户端请求服务器时,要保证客户端与服务器均受到。

TCP协议跟UDP相比是要保证可靠性(故TCP报头要比UDP报头复杂)。

在这里插入图片描述

源/目的端口号:表示数据是从哪个进程来,到哪个进程去;

4位首部长度:

1.如何将报头与有效载荷区分?

4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15*4=60**(默认情况下,TCP报头标准长度是4×5(从上到下五行)=20字节)**

4位首部长度基本单位是按4字节算的,若按一字节计算最大为1111=15,故TCP首部长度是15*4=60字节。

故我们要计算报头长度只需要将TCP首部长度除以TCP首部长度基本单位即可。例如通常情况下TCP包头标准长度为20字节,故此时报头长度为20/4=5,但又因为首部长度基本单位是4,故此处填写5的二进制0101。

2.如何将有效载荷发送给上层某个协议?

根据16位的目的端口号。

32位序号/32位确认序号:

可靠性:(保证双向均可靠(双向报文均需确认) 32位序号/32位确认序号)

**确认应答机制(ACK机制):**请求方发出请求后,应答方发回应答,此时保证应答方已知晓信息;当请求方向应答方再次发回确认信息后,此时保证请求方已经知晓应答方的应答,但若要保证应答方知晓信息就必须得到应答方回复,故此过程是无休无止的,因为总有一个报文是最新的(没有被经过确认)。故网络中不存在百分百可靠的协议。但只要在局部上该报文受到过确认就能保证该报文已经被确认。

数据在发送时的顺序和接收时顺序有可能不同,就有可能出现信息传达错误的问题。故要保证协议的稳定性就必须要保证数据发送和接收顺序相同,这个特性叫做数据按序到达

**32位序号(自身报文序号):**对TCP协议整体编号(发送报文时除了报文本身每个报文都携带一个编号),到达目的主机后可按照编号进行排序,此时不论目的主机以什么顺序接收报文均可以通过排序得知源主机发送报文顺序。

**32位确认序号(接收到的报文确认序号):**当发送方发送一个报文此时报文编号1,接收方确认后回复ACK2,表示编号2以前的所有报文均已收到,下次发送报文请从编号2开始。此时若一次性发送4个报文,编号从1-4,假如某一报文丢失,应答方返回ACK2,ACK3,ACK4,此时我们就可以知道4号报文丢失。

32位序号与32位确认序号承担的主要功能为:

1.确认应答机制;

2.丢包重查(超时重查):丢包时可通过确认应答机制查找到丢失的报文;

3.保证数据按序到达。

4.去重(接收方接收到重复数据时可根据序列号去重)。

16位窗口大小:用于确认报文应答时携带

TCP既有发送缓冲区也有接收缓冲区(当发送方一次性传送数据太多,接收方应用层来不及将数据读取,此时数据就放置于缓冲区中)

当发送方发送数据速度特别快时,接收方缓冲区已写满,后面发送的报文就会发生丢包,理论上丢包可通过32位序号与32位确认序号查到,可重新传输,但此种方法是一种浪费网络资源的行为(因从发送方到接收方要经过多层网络);故我们可通过实时得知接收缓冲区当去剩余缓冲区大小时就能避免丢包问题。

16位窗口大小:自身接收缓冲区当中剩余缓冲区大小。

**流量控制:**16位窗口大小主要是支持流量控制机制,让发送方按需发送,避免缓冲区越界问题。

用户发送数据交给操作系统,操作系统将数据放置网卡再交给网络。

6位标志位:

TCP协议是面向连接的,第一件事为建立连接。

SYN:通常情况下SYN被设置为0,但当SYN设置为1时代表这是连接建立的请求。

TCP建立连接采用的是三次握手。

TCP建立断开连接的是四次挥手。

FIN:通常情况下FIN被设置为0,但当FIN设置为1时代表这是断开连接的请求。

SYN和FIN不可同时设置。

ACK:保证此时报文为确认报文

URG紧急指针标志位,当URG被设置为1时代表报文后侧的16位紧急指针立刻生效,此指针指向的位置当前所表现的数据需要优先处理。URG通常与16位紧急指针搭配使用,我们通常将URG表示的紧急指针叫做带外数据

PSH:**催促报文标志位。**当确认报文应答返回窗口大小为0,表示当前接收缓冲区已满,此时发送方不能再发送报文又不能清楚的知道在过多久可以重新正常发送报文,此时发送方就可以发送催促报文携带PSH标志位,催促应用层读取接收缓冲区数据从而达到发送方尽快正常发送报文操作。

RST:当三次握手建立连接时最后一个报文丢失,客户端会认为建立连接成功,接下来就会向服务器发送数据,此时在服务器方面认为连接建立失败,当收到该客户端的报文时返回确定报文携带RST标志位,提示客户端建立连接失败,可重置连接(即再次建立连接),此时客户端可将建立失败连接处理重新建立新的连接。

连接管理机制

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接。

在这里插入图片描述

上图就是三次握手四次挥手的流程图。

建立连接与断开连接均需要基于状态机。

**TIME_WAIT状态:主动断开连接的一方必须得等待一段时间。**在等待的时间客户端所处的状态为TIME_WAIT。因为客户端发送的ACK可能丢失,若丢失服务器就接收不到客户端的确认报文,等待特定时间间隔后服务器会再次发送断开连接FIN,此时客户端会再次发送ACK,若客户端在一个特定时间间隔内再次收到服务器的FIN表明服务器没有接收到ACK,客户端需要重新发送ACK,若时间间隔过后没有接收到FIN,则表明服务器已接收到ACK,此时客户端就可断开连接。

必须要有TIME_WAIT的两个原因:

1.保证连接成功释放。四次挥手最后一个ACK有可能丢失,客户端必须处于TIME_WAIT状态等待一段时间,根据服务器是否再次发送FIN判断ACK是否正常被服务器接收,若正常接收客户端断开链接即可。

2.**保证在双向上数据在网络中尽可能地消散掉。**很有可能因为网络堵塞原因服务器应答给客户端的数据还在网络中没有传输过来。若没有TIME_WAIT状态,客户端一发送ACK就认为已经断开连接成功,就会导致客户端接收服务器应答信息不全,很可能出现数据还在网络中但连接已断开,这时数据到达客户端时已无意义;存在TIME_WAIT状态,客户端方等待一段时间至少可以保证因为网络堵塞等原因卡在网络中的数据最大可能地正常到达客户端。(客户端发起断开连接请求表明客户端方不再向服务器端发送信息,但此时客户端存在TIME_WAIT是为了最大化的接收来自服务器的数据)

**CLOSE_WAIT状态:**接收方被动接收主动发送断开连接请求方的断开连接请求。更多是因为对方将连接关闭但接收方认为该连接依旧存在。

三次握手:

此时我们思考第一个问题:为什么一定要三次握手,两次可以吗?

答案是不可以。原因是因为三次握手实现了确认应答机制,使客户端服务器均确认收到信息,若只有两次握手,则只能确保发送方(客户端)发出的报文已经被接收方(服务器)所接受,但服务器的应答报文不能确定是否被客户端接收。

且两次握手可能会导致服务器受到客户端海量的SYN攻击。此种情况发生于假如客户端发送的SYN正常被服务器接收,但是在应答时ACK丢失,此时服务器就会认为已经建立好了连接,但客户端认为服务器连SYN都没有接收到,就有可能存在客户端一直发送SYN的情况,此时服务器上建立了海量连接,但又因为其实根本没有建立好导致连接浪费,占用资源。

第二个问题:三次握手就一定能建立连接吗?

答案是不一定。因为三次握手保证了客户端发出报文已经被接收,服务器确认报文也已被客户端接收,但此时客户端发出的确认报文(ACK)有可能丢失。

所以三次握手是最大概率的建立连接成功,但不一定百分百建立成功(因最后一个ACK确认报文有可能丢失)。

第三个问题:三次握手为什么可以大概率的建立连接呢?

答案是当最后一个报文丢失时认为成功建立连接的是客户端(建立异常放置在客户端一方)。

解释:三次握手时若前两次握手丢失,不会影响,直接可认为三次握手没有成功,此时服务器不会建立连接。若第三次握手丢失,此时客户端认为连接建立成功,服务器没有接收到客户端的确认报文认为连接建立失败。又因为服务器是一对多,建立连接总有可能不成功,出现建立异常(即一方认为建立成功另一方认为没有建立成功),我们将建立异常放置在客户端一方较为合理(即客户端认为建立成功实际建立失败),若将建立异常放置服务器就有可能发生多个客户端发送海量SYN攻击,导致服务器挂掉。

第四个问题:那么为什么不是四次握手呢?

同理两次握手。建立异常放置在服务器一方。

连接建立成功之后双方为了维持连接会创造相应的数据结构。

四次挥手:

建立断开连接均需一方先发起请求,首先发起请求的是客户端。

为什么要四次挥手呢?

因为服务器客户端两方平等,断开连接需要两方均同意。因若只有一方同意断开连接的话,另一方认为连接还存在还会正常维护连接浪费资源,所以需要四次挥手双方同意达成协议断开连接。

TCP保证可靠性的机制有哪些?

1.面向连接(三次握手四次挥手);

2.确认应答机制(ACK机制);

3.按序到达;

4.超时重查:若确认序号没有丢失可根据返回的确认序号查找丢失报文,若确定序号丢失,超过一定时间没有响应时认为丢包异常。

5.流量控制:窗口大小返回自己的接收缓冲区剩余空间大小,减少丢包风险。

超时重传机制

第一种情况:

数据发送确认报文斜箭头表示这些操作均需要一定的时间。

在这里插入图片描述

上图所表示的丢包情况为真正意义上的的丢失数据,可能是因为网络拥堵等原因,数据无法到达主机B;那么主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发。

第二种情况:

在这里插入图片描述

以上为确认报文丢失,此时主机A在一个特定时间间隔内没有收到主机B的回复就会认为数据丢失主机B没有接收到数据,之后就会重新发送数据,此时主机B就会接收到重复数据。

因此就要求TCP协议能够识别出哪些包是重复的包,并且把重复的包丢弃。这时我们可以根据序列号进行去重。

超时时间如何确定?

最理想的情况下,找到一个最小的时间,保证“确认应答一定能在这个时间内返回”。但是这个时间的长短,随着网络环境的不同,是有差异的。如果超时时间设得太长,会影响整体的重传效率;如果超时时间设的太短,有可能会频繁发送重复的包。

TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间。

Linux中(BSD Unix和Windows也是如此),**超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍。**如果重发一次之后,荏苒得不到应答,等待2*500ms后在进行重传,如果仍然得不到应答,等待4×500ms进行重传,以此类推以指数形式递增;累积到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接。

滑动窗口:指的是无需等待确认应答就可以继续发送数据的最大值。(为了提高效率)

滑动窗口位于发送端的发送缓冲区中(但只是发送缓冲区的一部分),目前来看滑动窗口的大小跟接收缓冲区剩余空间大小一致。

滑动窗口决定了发送方一次向外发送数据的总量,那么滑动窗口的最终大小由什么决定?(学习了拥塞窗口后得到的结论)

**比较拥塞窗口和对方接收缓冲区剩余空间大小的较小值决定。**原因是一次性发送的数据量若大于拥塞窗口就会引起网络拥塞数据无法到达接收方,若大于接收缓冲区剩余空间大小就会导致缓冲区填满后后来的数据包直接丢失,故综合二者滑动窗口的大小需要取两者中的较小值。

滑动窗口主要解决什么问题?

提高效率。

滑动窗口为什么效率高?

是将多个段的等待时间重叠了。

滑动窗口怎么提高效率?

同属发送大量数据。

之前一发一收的方式性能较低。那么我们可以一次性发送多条数据,就可以大大提高性能(其实是将多个段的等待时间重叠在一起)提高性能的原因是在单位时间内网络当中能够投递的数据量增多,也就是网络的带宽变多。

在这里插入图片描述

**窗口大小指的是无需等待确认应答就可以继续发送数据的最大值。**上图的窗口大小就是4000个字节(四个段)

发送前四个段的时候,不需要等候任何ACK,直接发送。

收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据;以此类推;

在这里插入图片描述

注意:上图中滑动窗口的直接右移也有可能不准确,因为客户端发送数据增多,很有可能接收缓冲区剩余空间减少(此时滑动窗口需要减少段数,就有可能出现右边界限不移动左边界限移动的现象)或者直接为0,此时客户端就不能再发送信息,也就不能再右移了。

滑动窗口表示的是一次可以向接收方发送数据的总量,但是发送之后可以暂时不需要确认;

滑动窗口中放置的是已经发送的报文,但未收到确认报文。

操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉;

窗口越大,则网络的吞吐率就越高。

因发送报文有可能丢失,此时就需要进行超时重查,超时重查的前提条件为需要发送方在接收到确认报文之前将数据暂存,暂存位置为滑动窗口中。

滑动窗口左边为已经发送并且收到确认报文的数据。

滑动窗口右边可能为未发送数据。

那么如果出现了丢包,如何重传?

第一种情况:数据包已经抵达,ACK丢失。

在这里插入图片描述

上图这种情况只要接收到最后一个确认报文就可判断得知所有数据都已被主机B接收,前面的报文丢失没有关系可以通过后续的ACK得知。(接收缓冲区剩余空间大小可又最后一个确认报文携带的窗口大小得知)

第二种情况:数据包直接丢失。

在这里插入图片描述

快重传:

当某一段报文段丢失之后,发送端会一直收到1001这样的ACK,如果发送端主机连续三次收到了同样一个“1001”这样的应答,就会将对应的的数据1001-2000重新发送。这个时候接收端收到了1001之后,再次返回ACK就是7001了(因为2001-7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中。这种机制被称为“高速重发控制”或者“快重传”。

1.快重传的快体现在哪里?

连续收到三个相同的确认。

2.为什么已经有了超时重传还要有快重传?

因为返回三个确认时间比超时重传等待时间短,使用快重传能使客户端快速对丢失报文做出判断。

3.为什么有了快重传还要有超时重传?

因为当发送端只发送一个报文时,最多只能接受到一个ACK,故此时不能使用快重传,只能使用超时重传。

我们可以理解为超时重传为重传机制保底,快重传是锦上添花。

4.快重传是为了解决什么问题?

为了解决丢包问题及可靠性问题。

第一个问题:上图中为什么客户端重新发送丢失段报文后,服务器端接收成功后直接返回7001的确认报文?

因为中间报文数据包丢失后,丢失报文后面的报文被服务器端接收后返回的确认报文不再是3001、4001等(因若返回3001表明3001前的所有数据均已接收,与实际不符),而是丢失报文的首元素,以此告诉客户端该段报文数据包丢失需要重传;客户端重新传输成功后,服务器将会返回窗口大小字节数+1,即7001(表明7001前的所有数据均已接收)。接下来正常收发即可。

第二个问题:若窗口大小为3时,第二个报文丢失,能检测出来吗?

答案是可以。因滑动窗口就是以窗口大小为单位,客户端投递报文和服务器确认报文同时进行,所以客户端若丢失数据包会接收到服务器三次相同确认报文来判断重发哪段报文。

流量控制(以保证可靠性为目的)

**TCP支持根据接收端的处理能力,来决定发送端的发送速度。**这个机制叫做流量控制。

​ 接收端将自己可以接受的缓冲区大小放入TCP首部中的“窗口大小”字段,通过ACK端通知发送端;窗口大小字段越大,说明网络的吞吐量越高;接收端一旦发现自己的缓冲区快慢了,就会将窗口大小设置为一个更小的值通知给发送端;发送端接收到这个窗口之后,就会减慢自己的发送速度,如果接收端缓冲区满了,就会将窗口置为0,这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端(接收端告诉发送端)。但当过了重发超时的时间以后若还没有收到窗口更新的通知,发送端就会发送一个窗口探测的包(发送端发送探测的包到接收端),若接收方发送给发送方的通知在传送途中丢失时,就会导致无法进行通信,因此就需要发送机主端时不时的发送窗口探测包到接收端。

TCP首部中有一个16位的窗口字段,存放窗口大小信息,16位数字最大表示65535,那么TCP窗口最大就是65535字节吗?

默认情况下是。但若想提升窗口大小,TCP首部40字节选项中还包含了一个窗口扩大因子M,实际窗口大小是窗口字段的值左移M位(即在默认大小的基础上扩大2^M倍)。

拥塞控制(可靠性、提高效率):讨论数据在网络上是否会发生拥塞

慢启动:

虽然TCP有了滑动窗口能够高效可靠的发送大量的数据。但是在不清楚网络状况的情况下,直接发送大量数据,若出现大面积的数据丢失,此时就不单单是数据丢失,而是网络发生拥塞;出于可靠性考虑,我们应该要将丢失数据进行重传,可是在网络拥塞的情况下直接再次传输大量数据只会加剧网络拥塞程度。故在网络拥塞的情况下正确的方法是启动慢启动机制(以指数形式增长),先发少量的数据探探路,摸清当前网络的拥堵状况,再决定按照多大的速度传输数据。

在这里插入图片描述

上图中体现了网络拥塞状况下发送方发送少量数据试探网络拥塞状况的流程(呈指数增长,增长速度非常快)。上图主机A默认已经知道了现在网络发生了拥堵状况。

此处引入一个概念为拥塞窗口;发送开始的时候,定义拥塞窗口大小为1,每次收到一个ACK应答,拥塞窗口加1,每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小(接收窗口)作比较,取较小的值作为实际发送的窗口(滑动窗口)。

拥塞窗口相当于发送端的一个阈值,主机一旦发送数据超过这个值,网络就会发生拥塞。数据就不可能从A主机到B主机。

保证数据从A主机到B主机的前提条件为:

1.发送方发送数据数量不能超过拥塞窗口;

2.发送方发送数据量不能超过对方接收缓冲区剩余空间大小。

A主机要将数据正常发送至B主机,首先要将数据发送至网络上,故既不能造成网络拥塞也应该完完整整的被接收方接收。

滑动窗口决定了发送方一次向外发送数据的总量,那么滑动窗口的最终大小由什么决定?

**比较拥塞窗口和对方接收缓冲区剩余空间大小的较小值决定。**原因是一次性发送的数据量若大于拥塞窗口就会引起网络拥塞数据无法到达接收方,若大于接收缓冲区剩余空间大小就会导致缓冲区填满后后来的数据包直接丢失,故综合二者滑动窗口的大小需要取两者中的较小值。

怎么判断数据是否在网络上出现问题呢?

答案是是否出现大面积丢包,若出现则认为发生了网络拥塞,此时执行拥塞避免算法,拥塞避免算法的算法规则叫做慢启动。

像上面这样的拥塞窗口的增长速度,是指数级别的。“慢启动”只是初始慢,但增长速度特别快。所以为了不增长那么快,因此不能使拥塞窗口单纯的加倍,引入一个叫做慢启动的阈值,当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长。

拥塞控制算法

在这里插入图片描述

当TCP开始启动的时候,慢启动阈值等于窗口最大值(接收方缓冲区剩余空间大小)

在每次超时重发的时候(发生网络拥塞),慢启动阈值会变成原来的一半,同时拥塞窗口置为1。

少量的丢包,仅仅是触发超时重传;大量丢包,就认为网络拥塞。

当TCP通信开始后,网络吞吐量会逐渐上升,随着网络发生拥堵,吞吐量会立刻下降。

拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。

拥塞控制是为了解决什么问题?

避免数据在网络中大量丢包问题,提高可靠性。同时也会提高数据传输效率(因解决网络拥堵问题)。

延迟应答(提高效率)

延迟应答为什么能够提高效率?

原因是接收方接收到数据后会暂存接受缓存区,此时上层应用层同时也在读取接受缓存区信息,若能延迟应答,就会有极大概率应用层读走缓冲区数据,此时再返回给发送方接收窗口大小时就能更大些,那么发送方就能发送更多的数据从而提高效率。

注意:窗口(滑动窗口)越大,网络的吞吐量越大,传输效率越高。我们的目标是在保证网络不拥塞的情况下尽量提高传输效率。

那么所有的包都能延迟应答吗?肯定不是。需要通过数量和时间的限制。

数量限制:每隔N个包就应答一次。

时间限制:超过最大延迟时间就应答一次。

具体的数量和时间,依操作系统的不同也有差异;一般N=2,超时时间取200ms.

在这里插入图片描述

捎带应答(提高效率)

捎带应答指的是在之前学习的基础上接收方发送ACK确认报文时同时携带部分信息(因之前确认报文只是一个确认信息并没有实际其他信息,联系生活现实,确认的同时携带信息会提高效率)。

TCP总结

TCP核心功能主要为保证可靠性和提高性能(也有其他功能):

保证可靠性:

1.校验和

2.连接管理(三次握手四次挥手)

3.序列号(按序到达、去重)

4.确认应答机制

5.超时重发

6.流量控制:保证发送方发送数据时按照一定速度;

7.拥塞控制

提高性能:

1.滑动窗口

2.快重传

3.延迟应答

4.捎带应答

其他:

定时器(超时重传定时器,保活定时器,TIME_WAIT定时器等)

TCP三个概念

面向字节流

创建一个TCP的socket,同时在内核中创建了一个发送缓冲区和一个接收缓冲区

发送数据时,调用write时,数据会先写入发送缓冲区中;如果发送的字节数太长,会被拆分为多个TCP的数据包发出,如果发送字节数太短,就会先在缓冲区中等待,等到缓冲区长度差不多了,或者其他合适的时机发送出去。

接收数据时,数据也是从网卡驱动程序到达内核的接收缓冲区,然后应用程序可以调用read从缓冲区拿数据;

TCP的一个连接,既有发送缓冲区也有接收缓冲区,那么对于这一个连接,既可以读数据也可以写数据,这个概念叫做全双工

由于缓冲区的存在,TCP程序的读和写不需要一一匹配。例如:

写100个字节流数据时,可以调用一次write写100个字节,也可以调用100次write,每次写一个字节;

读100个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以一次read100个字节,也可以一次read一个字节,重复100次。

用户向网络中发送数据时并不是直接发送到网络中,而只是从用户区将数据拷贝到内核的操作系统的TCP的发送缓冲区中。数据什么时候发发多少都不是用户可决定的,这些都是TCP或者操作系统在合适的时间使用合适的方式发出去。

发送方假如每次发10个字节共发10次,接受方必须也是接收十次,即发送方怎么发送接收方就怎么接收时,这种方式叫做用户数据报;但当接收方接受次数完全由自己决定与发送方无关(即只要最终接收数据完整中间过程怎么接受完全由TCP自身决定)时,这种方式叫做面向字节流

TCP本质是面向字节流。应用层对于接收缓冲区的数据读取有一定格式的概念,但万一应用层对缓冲区中数据判断出现错误就会出现少读或者多读的情况,这种情况叫做字节流

TCP将数据发送目的接收方时是否要关心有效载荷中的内容?

答案是**不关心。**因TCP只要快速可靠的将数据送达即可。

粘包问题(包指的是应用层的数据包):由应用层解决,因TCP不需要知道有效载荷中的具体内容

粘包问题指的是我们在建立好连接后很有可能会同时发送多个报文,当连接上同时跑多个报文时就有可能出现前一个报文多读或少读进而导致后一个报文出现问题,这种情况就叫做粘包问题

TCP本质是面向字节流。应用层对于接收缓冲区的数据读取有一定格式的概念,但万一应用层对缓冲区中数据判断出现错误就会出现少读或者多读的情况,这种情况叫做字节流

那么如何避免粘包问题呢?

明确两个包之间的边界。又因为TCP根本不知道有效载荷中的内容具体是什么,TCP只需要将数据存入接收缓冲区中即可,所以TCP中数据边界与边界之间就只能通过应用层结识。

以下为为什么是应用层的解释:

在这里插入图片描述

应用层读取接收缓冲区中数据,若是GET方法则没有正文,读到空行继续读取下一个http报文即可;若为PSOT方法读到空行就表明HTTP报头已读完,可根据http报头属性中的content-length得知正文长度,故应用层可按照正文长度读取完整的有效数据(在应用层看来在接收缓冲区中读取的是一个一个的http报文),在TCP看来应用层读取了一个一个的字节,但应用层看来是读取了一个一个完整的http报文。所以应用层能完美的解决粘包问题。

避免粘包问题的具体情况具体方法:

1.定长。对于定长的包,保证每次都按照固定大小读取即可;例如Request结构是固定大小的,那么就从缓冲区从头开始按sizeof(Request)依次读取即可;

2.对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置(可根据报头属性中的content-length得知正文长度)。

3.自定义。程序员可在包与包之间自定义明确的分隔符(只要保证分隔符不与正文冲突即可)

思考:对于UDP协议来说,是否也有”粘包问题“?

答案是没有。因为UDP既是定长报头且还有16位的总长度,也就是说使用UDP协议既能知道报头长度以及有效载荷长度。但TCP只有4位首部长度,不过可通过序列号或者报头中content-length知道有效载荷长度。且站在应用层角度,使用UDP时要么收到完整的UDP报文要么不收。

TCP异常情况

1.进程终止:当建立好连接后正常运行时,客户端异常关闭了进程,此时连接会被释放掉(连接本身与文件相同)。当一个进程被关闭时,曾经打开建立的连接均要被自动释放掉,此时操作系统底层要执行四次挥手断开连接,操作系统底层仍会发FIN,与正常的断开连接无异。

2.机器重启:假如主机A在正常访问主机B,你不小心将主机A关机,此时进程关闭连接被释放,操作系统底层执行四次挥手操作。

3.机器掉电/网线断开:假如客户端正常访问服务器,此时客户端突然发生机器掉电/网线断开异常情况,这种情况下操作系统来不及进行四次挥手操作,对于客户端来说连接、操作系统均会瞬间断开,但对于服务器来说短期时间内还认为连接存在,那么服务器怎么发现该连接不存在呢?

第一种方法:服务器多次向客户端发送消息,客户端没有回应,TCP超时;

第二种方法:TCP内置一个保活定时器,会定期询问对方是否存在,如果不在会将连接释放;

第三种方法:应用层的某些协议也有检测机制。例如HTTP长连接中,也会定期检测对方的状态。

如果每次请求HTTP均要建立连接之后关闭连接,这种连接叫做短连接

短连接优点:建立连接响应一个资源后关闭连接,操作比较简单。缺点是:浪费资源,效率低。

那么优化短连接的方式为建立长连接。但长连接需要解决粘包问题,需要保证应用层完整接受所有信息。

长连接优点:一次在连接中可传送多个数据,所以长连接是为了提高效率。

基于TCP应用层协议

1.HTTP

2.HTTPS

3.SSH

4.Telnet

5.FTP

6.SMTP

当然也包括程序员自己写的TCP程序时自定义的应用层协议。

TCP/UDP对比

TCP是可靠的、面向连接的、基于字节流的传输层协议。UDP是不可靠的、面向数据报的传输层协议。

TCP应用场景:文件传输、重要状态更新、支付等应用场景。

UDP应用场景:对于高速传输及要求较高的通信领域。如QQ消息、视频、直播。

用UDP实现可靠传输(经典面试题)

可参考TCP的可靠机制,在应用层实现类似逻辑。

例如:引入序列号、保证数据顺序、去重;

引入确认应答,确保对端收到了数据;

引入超时重传,如果隔一段时间没有应答就重发数据。

……

TCP 相关实验

1.理解listen的第二个参数

构想一个情景:假如某个服务器一次能同时处理一万个连接,此时该服务器已经满载在同时处理一万个连接了,那么此时若还有新的连接想要连接该服务器该怎么办呢?服务器能够直接拒绝该连接吗?

答案当然是不能。所以TCP服务器本身一旦启动之后会在底层维护一个全连接队列(accpted队列),全连接队列维护已经建立好的连接将其暂时存放于此,当服务器将某些处理完的连接释放掉后,可从全连接队列中将等待连接按序拿上来继续进行处理。但是该等待队列不能没有也不能设置长度过长(因没有的话会导致服务器直接拒绝后来连接,若过长则会造成资源浪费)。

全连接队列是操作系统进行维护的,也仅仅只存在于TCP协议中,因只有TCP协议是面向连接的。

2.使用wireshark分析TCP通信流程

局域网:将所有主机都拿一根线连起来。局域网的通信原理是两个主机认为在跟对方直接通信,实际周围还有一群其他主机共享信息只不过没有影响。在局域网中每次都只能有一台主机发送消息,因若在局域网中主机A在跟主机B发消息,同时主机C在跟主机D发消息,此时在局域网中至少会有两个消息这时在局域网中相当于消息发生了碰撞。

所以在局域网中我们通常会说1.一个局域网就是一个碰撞域,为了保证局域网能够正常通信,局域网每次都只能有一个主机通信;2.任何时间任何一台主机发送消息,必须进行碰撞检测;3.一旦检测到数据碰撞也就意味着碰撞检测成功,这时就需要进行碰撞避免,碰撞避免就是等会再发。

那么在局域网中主机是怎么知道消息到底是不是发送给自己的呢?

可通过mac地址。

mac地址(局域网)与IP地址(广域网)的区别?

mac地址唯一,IP地址在广域网中唯一,但在局域网中会重复。

源IP地址 目的IP地址(不改变)

源mac地址 目的mac地址(一直在改变,去掉报头增加新报头)

那么为什么局域网中可以使用抓包工具抓包呢?

因为局域网中的所有消息其实都收到了,只是没有向上交付,原因是经过对比发现该消息不是给自己的。但是网卡可设置为混杂模式,网卡一旦被设置为混杂模式就会抓取所有的消息。但又因为消息种类太多,所以抓包工具需要限定规则来知道要知道哪些。比如可根据IP地址将端口号的方式来知道哪些数据。

基于碰撞域的这种网络我们称之为以太网。

猜你喜欢

转载自blog.csdn.net/weixin_42617262/article/details/88780897