【计算机网络】运输层
文章目录
- 运输层概述
- 运输层端口号、复用与分用的概念
- UDP和TCP的对比
- TCP的流量控制
- TCP的拥塞控制
- TCP超时重传时间的选择
- TCP可靠传输的实现
- TCP的运输连接管理
- TCP的连接建立(3次握手)
- TCP的连接释放(4次挥手)
- TCP报文段的首部格式
运输层概述
这里我们对运输层进行概述,之前文章所介绍的计算机网络体系结构中的物理层,数据链路层以及网络层,他们共同解决了将主机通过异构网络互联起来所面临的问题,实现了主机到主机的通信,
如图所示,局域网1上的主机与局域网2上的主机,通过互联的广域网进行通信,网络层的作用范围是主机到主机,但实际上在计算机网络中进行通信的真正实体是位于通信两端主机中的进程。
Ap是应用进程的英文缩写词,如何为运行在不同主机上的应用进程提供直接的通信服务,是运输层的任务,运输层协议又称为端到端协议,如图所示运输层的作用范围是应用进程到应用进程,也称为端到端。
接下来我们从计算机网络体系结构的角度来看运输层。这是通信双方应用层中的应用进程。假设AP1与AP4之间进行基于网络的通信,AP2与AP3之间进行基于网络的通信,在运输层需要不同的端口来对应不同的应用进程,然后通过网络层及其下层来传输应用层报文。如图所示,接收方的运输层通过不同的端口将收到的应用层报文交付给应用层中相应的应用进程。
需要注意的是这里的端口并不是指看得见摸得着的物理端口,而是指用来区分不同应用进程的标识符。为了简单起见,在学习和研究运输层时,我们可以简单的认为,运输层直接为应用进程间的逻辑通信提供服务。逻辑通信的意思是运输层之间的通信好像是沿水平方向传送数据,但事实上这两个运输层之间并没有一条水平方向的物理连接,要传送的数据是沿着图中上下多次的虚线方向传送的,运输层向高层用户屏蔽了下面网络核心的细节,如网络拓扑所采用的路由选择协议等,它是应用层看见的,就好像是在两个运输层实体之间,有一条端到端的逻辑通信信道,根据应用需求的不同,因特网的运输层为应用层提供了两种不同的运输层协议,面向连接的TCP协议和无连接的UDP协议。这两种协议就是本文要讨论的主要内容。
运输层端口号、复用与分用的概念
- 复用:就是可以重复使用的意思,即各个应用层协议都可以使用TCP协议;
- 分用:就是TCP根据端口号,将报文分给不同的应用进程。
关于端口号的概念:
接下来我们介绍发送方的复用和接收方的分用
如图所示,这是收发双方的应用进程:
- 发送方的某些应用进程所发送的不同应用报文,在运输层使用UDP协议进行封装,这称为UDP复用。
- 而另一些应用进程做发送的不同应用报文,在运输层使用TCP协议进行封装,这称为TCP复用
- 运输层使用端口号来区分不同的应用进程。不管是使用运输层的UDP协议,封装成的UDP用户数据报,还是使用TCP协议封装成的TCP报文段,在网络层都需要使用IP协议封装成IP数据报,这称为IP复用。
- IP数据报首部中协议字段的值,用来表明IP数据报的数据载荷部分,封装的是何种协议数据单元,取值为6表示封装的是TCP报文段,取值为17表示封装的是UDP用户数据报接收方的网络层
- 收到IP数据报后,进行IP分用,若IP数据报首部装协议字段的值为17,则把IP数据报的数据载荷部分所封装的UDP,用户数据报上交运输层的UDP
- 若协议字段的值为6,则把IP数据报的数据载荷部分所封装的TCP报文段,上交运输层的TCP。
- 运输层对UDP用户数据报进行UDP分用,对TCP报文段进行TCP分用,也就是根据端口号将它们交付给上层相应的应用进程。
下面我们给出TCP/IP体系的应用层常用协议所使用的运输层熟知端口号:
不管在运输层使用UDP还是TCP协议,在网络层都需要使用IP协议,IP数据报首部中协议字段的值,表明了IP数据报数据载荷部分封装的是何种协议数据单元。
接下来我们通过一个实例来进一步说明运输层端口号的作用
如图所示用户PC,DNS服务器,WEB服务器通过交换机进行互联,它们处于同一个以太网中,DNS服务器中记录有web域名所对应的IP地址,我们在用户PC中使用网页浏览器来访问WEB服务器的内容,在网页浏览器的地址栏中输入WEB服务器的域名:
过程如下:
-
用户PC中的DNS客户端进程,会发送一个DNS查询请求报文,其内容为域名www.porttest.com,所对应的IP地址是什么?
-
DNS查询请求报文,需要使用运输层的UDP协议封装成UDP用户数据报,其首部中的源端口字段值,在短暂端口号49151到65535中挑选一个未被占用的用来表示DNS客户端进程,例如49152。目的端口字段的值设置为53,这是DNS服务器端进程所使用的熟知端口号。之后将UDP、用户数据报封装在IP数据报中,通过以太网发送给DNS的服务器
-
DNS服务器端收到该数据报后,从中解封出UDP用户数据报,UDP首部中的目的端口号为53,这表明应将该UDP用户数据报的数据载荷部分,也就是DNS查询请求报文交付给本服务器中的DNS服务器端进程,DNS服务器端进程解析DNS查询请求报文的内容,然后按其要求查找对应的IP地址
-
之后会给用户PC发送DNS响应报文,及内容为域名www.porttest.com,所对应的IP地址是192.168.0.3,DNS响应报文需要使用运输层的UDP协议封装成UDP用户数据报,其首部中的源端口字段的值,设置为熟知端口号53,表明这是DNS服务器端进程所发送的UDP用户数据报,目的端口字段的值设置为49152,这是之前用户PC中发送DNS查询请求报文的 DNS客户端进程所使用的短暂端口号,之后将UDP用户数据报封装在IP数据报中,通过以太网发送给用户PC。
-
用户PC收到该数据报后,从中解封出UDP用户数据报,UDP首部中的目的端口号为49152,这表明应将该UDP用户数据报的数据载荷部分,也就是DNS响应报文交付给用户PC中的DNS客户端进程,DNS客户端进程解析DNS响应报文的内容。就可知道自己之前所请求的WEB服务器的域名所对应的IP地址为192.168.0.3。
-
现在用户PC中的HTTP客户端进程,可以向WEB服务器发送HTTP请求报文了。HTTP请求报文,需要使用运输层的TCP协议,封装成TCP报文段,其首部中的原端口字段的值在短暂端口号49151到65535中,挑选一个未被占用的用来表示HTTP客户端进程,例如仍然使用之前用过的49152目的端口字段的值设置为80,这是HTTP服务器端进程所使用的熟知端口号。之后将TCP报文段封装在IP数据报中,通过以太网发送给WEB服务器
-
WEB服务器收到该数据报后,从中解封出TCP报文段,TCP首部中的目的端口号为80,这表明应该将该TCP报文段的数据载荷部分,也就是HTTP请求报文交付给本服务器中的HTTP服务器端进程。HTTP服务器端进程,解析HTTP请求报文的内容,然后按其要求查找首页内容之后,会给用户PC发送HTTP响应报文,其内容是 HTTP客户端所请求的首页内容。HTTP响应报文需要使用运输层的TCP协议,封装成TCP报文段,其首部中的原端口号字段的值,设置为熟知端口号80,表明这是HTTP服务器端进程所发送的TCP报文段,目的端口字段的值设置为49152,这是之前用户PC中发送HTTP请求报文的HTTP客户端进程所使用的短暂端口号。之后将TCP报文段封装在IP数据报中,通过以太网发送给用户PC
-
用户收到该数据报后,从中解封出TCP报文段,TCP首部中的目的端口号为49152,这表明应该将该TCP报文段的数据载荷部分,也就是HTTP响应报文,交付给用户PC中的HTTP客户端进程,解析HTTP响应报文的内容,并在网页浏览器中进行显示,这样我们就可以在网页浏览器中看到WEB服务器所提供的首页内容了
内容小结如下:
UDP和TCP的对比
UDP和TCP是TCP体系结构运输层中的两个重要协议,如图所示,这是TCP/IP体系结构。它的运输层有两个非常重要的协议UDP和TCP。在使用TCP/IP体系结构的网络通信中,这两个协议的使用频率仅次于网际层的IP协议,TCP/IP体系结构应用层中的某些协议,有的需要使用运输层的TCP提供的服务,而另一些协议需要使用运输层的UDP提供的服务。
- UDP是用户数据报协议的英文缩写词
- TCP是传输控制协议的英文缩写词
接下来我们将从几个方面对这两个协议进行比较:
如图所示,这是因特网上的两台主机,他们在运输层使用UDP协议进行通信,纵坐标为时间:
-
使用UDP协议的通信双方可以随时发送数据。
-
使用TCP协议的通信双方在进行数据传输之前,必须使用三报文握手来建立TCP连接,TCP连接建立成功后才能进行数据传输结束后,必须使用四报文挥手来释放TCP连接。
-
需要注意的是这里所谓的连接是指逻辑连接关系,而不是物理连接。
综上所述,UDP是无连接的,而TCP是面向连接的
来看这个对比项:
- 这是某个局域网上的需要UDP协议进行通信的4台主机,其中任何一台主机都可向其他三台主机发送广播,也可以向某个多播组发送多播,还可以向某台主机发送单播,也就是说UDP支持单播多播以及广播。换句话说,UDP支持一对一,一对多以及一对全的通信。
- 再来看使用TCP协议的情况,使用TCP协议的通信双方在进行数据传输之前,必须使用三报文握手来建立TCP连接,TCP连接建立成功后,通信双方之间就好像有一条可靠的通信信道,通信双方使用这条基于TCP连接的可靠信道进行通信,很显然 TCP仅支持单播,也就是一对一的通信。
接下来我们来对比这两个协议对应用报文的处理:
- 先来看使用UDP协议的情况,发送方的应用进程,将应用层报文交付给运输层的UDP,UDP直接给应用层报文,添加一个UDP首部,使之成为UDP用户数据报,然后进行发送。需要说明的是为了简单起见,我们忽略运输层下面的各层处理,接受方的UDP收到该UDP用户数据报后,去掉UDP首部,将应用层报文交付给应用进程,也就是说UDP对应用进程交下来的报文,既不合并也不拆分,而是保留这些报文的边界。换句话说,UDP是面向应用报文的
- 再来看使用TCP协议的情况,发送方的TCP把应用进程交付下来的数据块,仅仅看作是一连串的无结构的字节流,TCP并不知道这些待传送的字节流的含义,仅将他们编号并存储在自己的发送缓存中。TCP根据发送策略,从发送缓存中提取一定数量的字节,构建TCP报文段并发送。接收方的TCP,一方面从所接收到的TCP报文段中取出数据载荷部分并存储在接收缓存中,一方面将接收缓存中的一些字节交付给应用进程,TCP不保证接收方应用进程所收到的数据块与发送方应用进程和发出的数据块具有对应大小的关系。例如发送方应用进程交给发送方的TCP,共10个数据块,但接收方的TCP可能只用了4个数据块,就把收到的字节流交付给了上层的应用进程,但接收方应用进程收到的字节流必须和发送方应用进程发出的字节流完全一样。当然接收方的应用进程必须有能力识别收到的字节流,把它还原成有意义的应用层数据,也就是说 TCP是面向自字节流的,这正是TCP实现可靠传输,流量控制以及拥塞控制的基础。
需要说明的是为了突出示意图的要点,我们只画出了一个方向的数据流,在实际网络中基于TCP连接的两端,可以同时进行TCP报文段的发送和接收,也就是全双工通信。另外图中TCP报文段的数据部分只包含了几个字节,实际当中一个TCP报文段包含上千个字节是很常见的。
再来看下一个对比项:
- 我们曾介绍过TCP/IP体系结构的网际层向其上层提供的是无连接不可靠的传输服务,当运输层使用UDP协议时,向其上层提供的也是无连接不可靠的传输服务,发送方给接收方发送UDP用户数据报,若传输过程中,用户数据报受到干扰而产生误码,接收方UDP可以通过该数据报首部中的校验和字段的值,检查出产生误码的情况,但仅仅丢弃该数据报,其他什么也不做。发送方给接收方发送UDP用户数据报,如果该数据报被因特网中的某个路由器丢弃了,发送方UDP不做任何处理,因为UDP向上层提供的是无连接不可靠的传输服务。因此对于UDP用户数据报出现的误码和丢失等问题,UDP并不关心。基于UDP的这个特点,UDP适用于实时应用,例如IP电话、视频会议等。
- 再来看使用TCP协议的情况,尽管网际层中的IP协议向上层提供的是无连接不可靠的传输服务,也就是说 IP数据报可能在传输过程中出现丢失或误码,但只要运输层使用TCP协议,就可向其上层提供面向连接的可靠传输服务。我们可将其想象成使用TCP协议的收发双方,基于TCP连接的可靠性到进行数据传输,不会出现误码丢失、乱序以及重复等传输差错。TCP适用于要求可靠传输的应用,例如文件传输。
最后我们再来对比一下UDP用户数据报的首部与TCP报文段的首部:
- 一个UDP用户数据报由首部和数据载荷两部分构成,其首部格式如图所示仅有4个字段,每个字段长度为2个字节。由于UDP不提供可靠传输服务,它仅仅在网际层的基础上添加了用于区分应用进程的端口,因此他的首部非常简单,仅有8个字节
- 1个TCP报文段由首部和数据载荷两部分构成,其首部格式如图所示,这比UDP用户数据报的首部复杂的多,其最小长度为20字节,最大长度为60字节,这是因为TCP要实现可靠传输,流量控制、拥塞控制等服务,其首部自然会比较复杂,首部中的字段比较多,首部长度也比较长
内容小结如下:
TCP的流量控制
这里我们介绍TCP的流量控制:
- 一般来说我们总是希望数据传输的更快一些
- 但如果发送方把数据发送的过快,接收方就可能来不及接收,这就会造成数据的丢失
- 所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收
- 利用滑动窗口机制,可以很方便的在TCP连接上实现对发送方的流量控制
我们来举例说明,假设主机A和B是因特网上的两台主机,它们之间已经建立了TCP连接,A给B发送数据,B对A进行流量控制,这是主机A中带发送数据的字节序号,假设主机A发送的每个TCP报文段可携带100字节数据,因此图中每个小格子表示100个字节数据的序号,在主机A和B建立TCP连接时,B告诉A我的接收窗口为400,因此主机A将自己的发送窗口也设置为400,这意味着主机A在未收到主机B发来的确认时,可将序号落入发送窗口中的全部数据发送出去。
接下来我们举例说明主机B对A的流量控制:
- 主机A将发送窗口内序号1~ 100的数据,封中成一个TCP报文段发送出去,发送窗口内还有300字节可以发送。
- 这里的seq是TCP报文段首部中的序号字段,取值1,表示TCP报文段数据载荷的第一个字节的序号是1,这里的DATA表示这是TCP数据报文段
- 主机A将发送窗口内序号101~ 200的数据,封中成一个TCP报文段发送出去,发送窗口内还有200字节可以发送
- 主机A将发送窗口内,序号201~300的数据,封中成一个TCP报文段发送出去,但该报文段在传输过程中丢失了,主机A发送窗口内还有100字节可以发送。
- 主机B对主机A所发送的201号以前的数据进行累计确认,并在该累计确认中将窗口字段的值调整为300,也就是对主机A进行流量控制。
- 这里的大写ACK是TCP报文段首部中的标志位,取值1,表示这是一个TCP确认报文段,小写ack是TCP报文段首部中的确认号字段,取值201,表示序号201之前的数据已全部正确接收,现在希望收到序号201及其后续数据。RWND是TCP报文段首部中的窗口字段,取值300,表示自己的接收窗口大小为300。
- 主机A收到该累计确认后,将发送窗口向前滑动,使已发送并收到确认的这些数据的序号,移出发送窗口。
-
由于主机B在该累计确认中,将自己的接收窗口调整为了300,因此主机A相应的将自己的发送窗口调整为300。目前主机A发送窗口内的序号为201~ 500,也就是主机A还可以发送这300字节,其中201~ 300号字节是已发送的数据,若重传计时器超时,他们会被重传。301号到400号字节,以及401号到500号字节还未被发送,可被分别封中在一个TCP报文段中发送。主机A现在可将发送缓存中序号1~200的字节数据全部删除了,因为已经收到了主机B对他们的累计确认。
-
主机A将发送窗口内序号301~ 400个数据,封中成一个TCP报文段发送出去,发送窗口内还有100字节可以发送
-
主机A将发送窗口内序号401~500的数据,封中成一个TCP报文段发送出去,至此序号落在发送窗口内的数据已经全部发送出去了,不能再发送新数据了。
-
现在发送窗口内序号201~300,这100个字节数据的重传计时器超时了,主机A将它们重新封中成一个TCP报文段发送出去,暂时不能发送其他数据。
-
主机B收到该重传的TCP报文段后,对主机A所发送的501号以前的数据进行累计确认,并在该累计确认中将窗口字段的值调整为100。这是主机B对主机A进行的第二次流量控制。
-
主机A收到该累计确认后,将发送窗口向前滑动,使已发送并收到确认的这些数据的序号移出发送窗口。由于主机B在该累计确认中将自己的接收窗口调整为了100,因此主机A相应的将自己的发送窗口调整为100。目前主机A发动窗口内的序号为501~ 600,也就是主机A还可以发送这100字节,主机A现在可将发送缓存中序号201~ 500的字节数据全部删除了,因为已经收到了主机B对他们的累积确认
-
主机A将发送窗口内序号501~600的数据,封中成一个TCP报文段发送出去,至此序号落在发送窗口内的数据已经全部发送出去了,不能再发送新数据了。主机B对主机A所发送的601号以前的数据进行累计确认,并在该领域确认中将窗口字段的值调整为0。这是主机B对主机A进行的第三次流量控制。
-
主机A收到该累计确认后,将发送窗口向前滑动,使已发送并收到确认的这些数据的序号,移出发送窗口。由于主机B在该累计确认中将自己的接收窗口调整为了0,因此主机A相应的将自己的发送窗口调整为0。
-
目前主机A不能再发送一般的TCP报文段了,主机A现在可将发送缓存中序号501~600的字节数据全部删除了,因为已经收到了主机B对他们的累计确认
-
假设主机B向主机A发送了0窗口的报文段后不久,主机B的接收缓存又有了一些存储空间,于是主机B向主机A发送了接收窗口等于300的报文段,然而这个报文段在传输过程中丢失了,主机A一直等待主机B发送的非0窗口的通知,而主机B也一直等待主机A发送的数据,如果不采取措施,这种互相等待而形成的死锁局面将一直持续下去。
-
为了解决这个问题,TCP为每一个连接设有一个持续计时器,只要TCP连接的一方,收到对方的0窗口通知,就要启动持续计时器。若持续计时器超时,就要发送一个0窗口探测报文,仅携带一字节的数据,而对方在确认这个探测报文段时,给出自己现在的接收窗口值。如果接收窗口仍然是0,那么收到报文段的一方要重新启动持续计时器,如果接收窗口不是0,那么死锁的局面就可以被打破了。
在本例中,主机A收到零窗口通知时,就要启动一个持续计时器,当持续计时器超时,主机A立刻发送一个仅携带一字节数据的零窗口探测保温段,假设主机B此时的接收窗口又为0了,主机B就在确认零窗口探测报文段时,给出自己现在的接收窗口值为零。主机A再次收到零窗口通知,就要再次启动一个持续计时器,当持续计时器超时,主机A立刻发送一个零窗口探测报文段,假设主机B此时的接收缓存又有了一些存储空间,于是将自己的接收窗口调整为了300,主机B就在确认零窗口探测报文段时,给出自己现在的接收窗口值为300,这样就打破了死锁的局面。
同学们可能会有这样的疑问,主机A所发送的零窗口探测报文段到达主机B时,如果主机B此时的接收窗口仍然为0,那么主机B根本就无法接受该报文段,又怎么会针对该报文段给主机A发回确认呢?实际上TCP规定即使接收窗口为0,也必须接受零窗口探测报文段,确认报文段,以及携带有紧急数据的报文段。
请大家再来思考一下这个问题。如果零窗口探测报文段丢失了,会出现怎样的问题呢?还能否打破死锁的局面呢?回答是肯定的,因为零窗口探测报文段也有重传计时器,当重传计时器超时后,零窗口探测报文段会被重传。
内容小结如下:
TCP的拥塞控制
首先来看拥塞控制的基本概念:
我们使用上图来说明拥塞控制的作用:
- 横坐标是输入负载,代表单位时间内输入给网络的分组数量,纵坐标是吞吐量,代表单位时间内从网络输出的分组数量,具有理想拥塞控制的网络,在吞吐量达到饱和之前,网络吞吐量应等于所输入的负载,故吞吐量曲线是45度的斜线,但当输入负载超过某一限度时,由于网络资源受限,吞吐量就不再增长,而保持水平线,也就是吞吐量达到饱和,这就表明输入的负载中有一部分损失掉了。例如输入到网络中的某些分组,被某个节点丢弃了。虽然如此,在这种理想的拥塞控制作用下,网络的吞吐量仍然维持在其所能达到的最大值。
- 然而实际的网络情况就很不同了。我们再来看这条吞吐量曲线,随着输入负载的增大,网络吞吐量的增长率逐渐减小,也就是在网络吞吐量还未达到饱和时,就已经有一部分的输入分组被丢弃了。当网络的吞吐量明显的小于理想的吞吐量时,网络就进入了轻度拥塞的状态。
- 更值得注意的是,当输入负载到达某一数值时,网络的吞吐量反而随输入负载的增大而减小,这时网络就要进入了拥塞状态,当输入负载继续增大到某一数值时,网络的吞吐量就要减小为零,此时网络就要无法工作了,这就是所谓的死锁。因此进行拥塞控制是非常有必要的。实际的拥塞控制曲线应该尽量接近理想的拥塞控制曲线。
接下来我们介绍TCP的4种拥塞控制算法,他们分别是:
- 慢开始
- 拥塞避免
- 快重传
- 快恢复
我们来举例说明TCP这4种拥塞控制算法的基本原理,为了集中精力讨论拥塞控制,我们假定如下条件:
- 一数据是单方向传送的,而另一个方向只传送确认。
- 二接收方总是有足够大的缓存空间,因而发送方发送窗口的大小仅由网络的拥塞程度来决定。
- 三以TCP最大报文段MSS的个数为讨论问题的单位,而不是以字节为单位。
假设这是TCP的发送方和接收方,发送方给接收方发送TCP数据报文段,接收方收到后给发送方发送TCP确认报文段:
我们前面说过送方发送窗口的大小仅由网络的拥塞程度来决定,所以这里发送窗口的大小和拥塞窗口一样的大,正常情况下并不一定是这样的。
首先来看慢开始算法,为了更清楚的显示出拥塞控制过程,我们还可以绘制这样一幅拥塞窗口随传输轮次变化的图,横坐标为传输轮次,传输轮次是指发送方给接收方发送数据报文段后,接收方给发送方发回相应的确认报文段。一个传输轮次所经历的时间,其实就是往返时间。请注意往返时间并非是恒定的数值,使用传输轮次是为了强调把拥塞窗口所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个报文段的确认。
纵坐标是拥塞窗口,它会随网络拥塞程度以及所使用的拥塞控制算法动态变化。
-
在TCP双方建立逻辑连接关系时,拥塞窗口的值被设置为1,我们在图上标出传输轮次0时的拥塞窗口值为1,另外还需设置慢开始门限的初始值,本例采用16,我们也将它在图中标出,在执行慢开始算法时,发送方每收到一个对新报文段的确认时,就把拥塞窗口值加1,然后开始下一轮的传输,当拥塞窗口值增长到慢开始门限值时,就要改为执行拥塞避免算法。
-
由于发送方当前的拥塞窗口值是1,而发送窗口值等于拥塞窗口值,因此发送方当前只能发送1个TCP数据报文段,换句话说,拥塞窗口值是几,就能发送几个数据报文段,如图所示发送方发送0号数据报文段,接收方收到后给发送方发回对0号报文段的确认报文段,
-
发送方收到该确认报文段后,将拥塞窗口值加1增大到2,我们在图中标出该值,这意味着发送方现在可以发送1~ 2号共两个数据报文段,接收方收到后给发送方发回对1~2号报文段的确认报文段,
-
发送方收到后将拥塞窗口值加2增大到4。我们在图中标出该值,发送方现在可以发送3~ 6号共4个数据报文段,接收方收到后给发送方发回,对3~6号报文段的确认报文段,发送方收到后将拥塞窗口值加四增大到8
-
我们在图中标出该值发送方现在可以发送7~14号,共8个数据报文段,接收方收到后给发送方发回,对7 ~ 14号报文段的确认报文段,发送方收到后将拥塞窗口值加8增大到16,我们在图中标出该值,发送方当前的拥塞窗口值已经增大到了慢开始门限值之后,我们要改用拥塞避免算法,也就是每个传输轮次结束后,拥塞窗口值只能线性加一,而不像慢开始算法那样,每个传输轮次结束后,拥塞窗口值按指数规律增长
-
发送方现在可以发送15 ~ 30号,共16个数据报文段,接收方收到后给发送方发回,对15 ~ 30号报文段的确认报文段,发送方收到后将拥塞窗口值加一增大到17。我们在图中标出该值现在可以发送31~47号,共17个数据报文段,接收方收到后给发送方发回,对31 ~47号报文段的确认报文段,发送方收到后将拥塞窗口值加一增大到18。我们在图中标出该值
-
随着传输轮次的增加,拥塞窗口值每轮次都线性加一,例如当前拥塞穿口值增加到了24,发送方现在可以发送171~194号,共24个数据报文段。假设这24个数据报文段在传输过程中丢失了几个,这必然会造成发送方对这些丢失报文段的超时重传。发送方以此判断网络很可能出现了拥塞,需要进行以下工作。
- 1.将慢开始门限值更新为发生拥塞时拥塞窗口值的一半,网络发生拥塞时的拥塞窗口值是24,因此更新慢开始门限值为该值的一半,即12
- 2.将拥塞窗口值减小为1,并重新开始执行慢开始算法,如图所示,当慢开始执行到拥塞窗口值增大到新的慢开始门限值时,就要停止使用慢开始算法,转而执行拥塞避免算法。
- 1.将慢开始门限值更新为发生拥塞时拥塞窗口值的一半,网络发生拥塞时的拥塞窗口值是24,因此更新慢开始门限值为该值的一半,即12
通过本例可以看出,我们可以总结出:
- TCP发送方一开始使用慢开始算法,让拥塞窗口值从一开始按指数规律增大
- 当拥塞窗口值增大到慢开始门限值时停止使用慢开始算法,转而执行拥塞避免算法,让拥塞窗口值按线性加1的规律增大
- 当发生超时重传时,就要判断网络很可能出现了拥塞,采取相应的措施,一方面将慢开始门限值更新为发生拥塞时拥塞窗口值的一半,另一方面将拥塞窗口值减小为一,并重新开始执行慢开始算法。
- 拥塞窗口值又从一开始按指数规律增大,当增大到了新的慢开始门限值时,停止使用慢开始算法,转而执行用在避免算法,让拥塞窗口值按线性加1的规律增大。
需要注意的是:
- 慢开始是指一开始向网络注入的报文段少,而并不是指拥塞窗口值增长速度慢,
- 拥塞避免,也并非指完全能够避免营塞。而是只在拥塞避免阶段将拥塞窗口值控制为按线性规律增长,使网络比较不容易出现拥塞
慢开始和拥塞避免是1988年就提出的TCP拥塞控制算法,也就是TCP的Tahoe版本,1990年又增加了两个新的拥塞控制算法,以便改进TCP的性能,这就是快重传
和快恢复
,被称为TCP的Reno版本。有时个别报文段会在网络中丢失,但实际上网络并未发生拥塞,这将导致发送方超时重传,并误认为网络发生了拥塞。
例如在之前的例子中,当拥塞窗口值增大到24时,发生了超时重传,而网络此时并没有发生拥塞,但是发送方却误认为网络发生了拥塞,于是发送方把拥塞窗口值减小为1并错误的启动慢开始算法,因而降低了传输效率。
采用快重传算法,可以让发送方尽早知道发生了个别报文段的丢失。所谓快重传是发送方尽快进行重传,而不是等超时重传计时器超时再重传
- 这就要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,
- 即使收到了失序的报文段,也要立即发送,对已收到的报文段的重复确认,
- 发送方一旦收到三个连续的重复确认,就将相应的报文段立即重传,而不是等该报文段的重传计时器超时再重传
我们来举例说明快重传算法:
- 发送方发送1号数据报文段,接收方收到后给发送方发回,对1号报文段的确认,在该确认报文段到达发送方之前,发送方还可以将发送窗口内的2号数据报文段发送出去,
- 接收方收到后给发送方发回对2号报文段的确认。
- 在该确认报文段到达发送方之前,发送方还可以将发送窗口内的3号数据报文段发送出去,但该报文段丢失了,接收方自然不会给发送方发回针对该报文段的确认,
- 发送方还可以将发送窗口内的4号数据报文段发送出去,接收方收到后,发现这不是按序到达的报文段,因此给发送方发回,针对2号报文段的重复确认,表明我现在希望收到的是三号报文段,但是我没有收到三号报文段,而是收到了未按序到达的报文段,
- 发送方还可以将发送窗口内的5号数据报文段发送出去,接收方收到后发现这不是按序到达的报文段,因此给发送方发回针对2号报文段的重复确认,
- 发送方还可以将发送窗口内的6号数据报文段发送出去,接收方收到后发现这不是按需到达的报文段,因此给发送方发回针对2号报文段的重复确认,至- 此发送方会收到三个连续的对二号报文段的重复确认,就要立即重传三号报文段,
- 接收方收到后给发送方发回针对6号报文段的确认,表明序号到六为止的报文段都正确接收了,这样就不会造成对三号报文段的超时重传,而是提早进行了重传。
- 对于个别丢失的报文段,发送方不会出现超时重传,也就不会误认为出现了拥塞,而错误的降低拥塞窗口值为最小值一,使用快重传可以使整个网络的吞吐量提高约20%
再来看快恢复算法,发送方一旦收到三个重复确认,就知道现在只是丢失了个别的报文段,于是不启动慢开始算法,而是执行快恢复算法,
发送方将慢开始门限值和拥塞窗口值调整为当前窗口值的一半,开始执行拥塞避免算法,
也有的快恢复实现,是把快恢复开始时的拥塞窗口值再增大一些,也就是等于新的慢开始门限值加三。这样做的理由是;
- 既然发送方收到三个重复的确认,就要表明有三个数据报文段已经离开了网络,
- 这三个报文段不再消耗网络资源,而是停留在接收方的接收缓存中。
- 可见现在网络中不是堆积的报文段,而是减少了三个报文段,因此可以适当把用塞窗口值扩大一些。
接下来我们给出TCP拥塞窗口值,在拥塞控制时的变化情况举例,里面包含了TCP拥塞控制的4种算法:
-
TCP发送方一开始使用慢开始算法,让拥塞窗口值从一开始按指数规律增大,当增大到慢开始门线初始值时,停止使用慢开始算法,转而执行拥塞避免算法,让拥塞窗口值按线性加1的规律增大。
-
当发生超时重传时,就要判断网络可能出现了拥塞,采取相应的措施,一方面将慢开始门限值,更新为发生拥塞时拥塞窗口值的一半,另一方面将拥塞窗口值减小为一,并重新开始执行慢开始算法。
-
拥塞窗口值又从一开始按指数规律增大,当增大到了新的慢开始门限值时,停止使用慢开始算法,转而执行拥塞避免算法,让拥塞窗口值按线性加1的规律增大。
-
当发送方收到三个重复的确认时,就要进行快重传和快恢复,也就是更新慢开始门限值为当前拥塞窗口值的一半,并将拥塞窗口值也取为新的慢开始门限值,转而执行拥塞避免算法,让拥塞窗口值按线性加1的规律增大。
TCP超时重传时间的选择
超时重传时间的选择是TCP最复杂的问题之一。我们来举例说明,假设主机A和B是因特网上的两台主机,他们之间已经建立了TCP连接,纵坐标为时间,现在主机A给主机B发送TCP数据报文段0,并记录下当前的时间。主机B收到后给主机A发送相应的确认报文段。主机A收到确认报文段后,记录下当前的时间,那么主机A记录下的这两个时间,它们的差值,就是报文段的往返时间RTT由于这是第0个报文段的RTT,我们就用RTT0来表示。试想一下,如果我们将超时重穿时间,RTO的值设置的比RTT0的值小,会出现怎样的情况?很显然这会引起报文段不必要的重传,使网络负荷增大。
那么如果将超时重传时间,RTO的值设置的远大于RTT0的值,又会出现怎样的情况?很显然这会使重传推迟的时间太长,使网络的空闲时间增大,降低了传输效率。
综合上述两种情况,我们可以得出这样的结论,超时重传时间RTO的值应该设置为略大于报文段往返时间RTT的值。至此同学们可能会觉得超时重传时间的选择也并不是很复杂,然而 TCP下层是复杂的互联网环境,主机A所发送的报文段可能只经过一个高速率的局域网,也有可能经过多个低速率的网络,并且每个IP数据报的转发路由还可能不同。
例如现在主机A给主机B发送TCP数据报文段一,主机B收到后,给主机A发送相应的确认报文段,主机A这次测得的报文段往返时间RTT一如图所示,显然RTT1远大于RTT0,如果超时重装时间RTO还是我们之前所确定的略大于RTT0的话,这对于数据报文段1是不合适的,会造成该报文段不必要的重传。
这样看来超时重传时间的选择确实不那么简单了,我们不能直接使用某次测量得到的RTT样本来计算超时重装时间RTO,但是我们可以利用每次测量得到的RTT样本,计算加权平均往返时间RTTS,这样可以得到比较平滑的往返时间。当测量到第一个RTT样本时,RTTS的值直接取为第一个RTT样本的值,以后每测量到一个RTT样本时,都按该公式来计算新的RTT S值。
在上式中阿尔法的取值大于等于0,且小于一,若阿尔法很接近于零,则新RTT样本对RTTS的影响不大,若阿尔法很接近于一则新RTT样本,对RTTS的影响较大,已成为建议标准的RFC6298,推荐的阿尔法值为1/8,即0.125,用这种方法得出的加权平均往返时间RTTS的值就要比测量出的RTT的值更加平滑。
显然超时重穿时间,RTO的值应略大于加权平均往返时间RTTS的值。
下面我们给出RFC6298建议使用的超时重传时间RTO的计算公式,该公式中的RTTS是加权平均往返时间,我们刚刚介绍过它的计算方法,RTTD是RTT偏差的加权平均,计算方法如下,当测量到第一个RTT样本时,RTTD的值取为该样本值的一半,以后每测量到一个RTT样本时,都按该公式来计算新的RTTD的值。在上式中贝塔的取值大于等于0且小于1,已成为建议标准的RFC6298推荐的贝塔值为1/4,即0.25。我们可以发现不管是RTTS还是RTTD都是基于所测量到的RTT样本进行计算的。如果所测量到的RTT样本不正确,那么所计算出的RTTS和RTTD自然就要不正确,进而所计算出的超时重穿时间RTO也就不正确。
然而往返时间RTT的测量确实是比较复杂的。我们来举例说明,主机A给主机B发送TCP数据报文段,但该报文段在传输过程中丢失了,当超时重传计时器超时后,主机A就重传该报文段,主机B收到后给主机A发送确认报文段。现在问题来了,主机A收到该确认报文段后,无法判断该报文段是对原报文段的确认,还是对重传报文段的确认。该报文段实际上是对重传报文段的确认,也就是说正确的RTT应该是这一段时间。但是如果主机A误将该确认当做是对原报文段的确认,也就是误认为这段时间是RTT则所计算出的RTTS和RTO就会偏大,降低了传输效率。
再来看另一种情况,主机A给主机B发送TCP数据报文段,主机B收到后给主机A发送确认报文段,由于某种原因,该确认报文段没有在正常时间内到达主机A这必然会导致主机A对之前所发送的数据报文段的超时重传。现在问题又来了,主机A收到迟到的确认报文段后,无法判断该报文段是对原报文段的确认,还是对重传报文段的确认。该报文段实际上是对原报文段的确认,也就是说正确的RTT应该是这一段时间。但是如果主机A误将该确认当做是对重传报文段的确认,也就是误认为这段时间是RTT,则所计算出的RTTS和RTO就会偏小,这会导致报文段没有必要的重传,增大网络负荷。
通过这两个例子可以看出,当发送方出现超时重传后,收到确认报文段时,是无法判断出该确认到底是对原报文段的确认,还是对重传报文段的确认,也就是无法准确测量出RTT,进而无法正确计算超时重传时间RTO。因此针对出现超时重传时,无法测准往返时间RTT的问题,Karn提出了一个算法,在计算加权平均往返时间RTTS时,只要报文段重传了,就要不采用其往返时间RTT样本,也就是出现重传时,不重新计算RTTS,进而超时重传时间RTO也不会重新计算。然而这要引起了新的问题,设想出现这样的情况,报文段的时延突然增大了很多,并且之后很长一段时间内都会保持这种时延,因此在原来得出的重传时间内,不会收到确认报文段,于是就重传报文段。根据Karn算法,不考虑重传的报文段的往返时间样本,这样超时重传时间就要无法更新,这会导致报文段反复被重传。因此要对Karn算法进行修正,方法是报文段每重传一次,就把超时重传时间RTO增大一些,典型的做法是将新RTO的值取为旧RTO值的两倍。
接下来我们举例说明,TCP超时重传时间的计算,这是测量得到的第一个RTT样本RTT1。根据RTTS1的计算公式可知RTTS1的值.根据RTTDE的计算公式,可知RTTD1的值在根据IPO的计算公式可计算出RTO1的值,这是测量得到的第二个RTT2,根据RTTS2的计算公式和阿尔法的值和写出计算RTTS2的表达式,将之前计算出的RTTS1的值和本次测量得到的RTT2的值代入干涉,可计算出RTTS2的值。根据RTTD的计算公式和贝塔的值,可写出计算RTTD2的表达式,将之前计算出的RTTD1,RTTS,1以及本次测量得到的RTT2的值,代入该式,可计算出RTTD2的值。再根据RTO的计算公式,可计算出RTO2的值。假设这是测量得到的第3个和第4个RTT样本。计算一下RTO3和RTO4的值分别是多少?答案如图所示,相信大家都能正确解答。假设这是测量得到的第5个RTT样本,但是根据RTO4的值可知,在收到确认之前就会产生超时重传。我们之前介绍过,若出现超时重传,则不采用上述公式计算RTO,而是将新RTO的值取为旧RTO值的两倍。因此RTO5的值取为两倍的RTO4的值。
内容小结如下:
TCP可靠传输的实现
TCP基于以字节为单位的滑动窗口来实现可靠传输
我们来举例说明,这是因特网上的两台主机,他们之间已经建立了一个TCP连接,为了简单起见,我们假定数据传输只在一个方向进行,换句话说,发送方给接收方发送TCP数据报文段,接收方给发送方发送相应的TCP确认报文段,这样的好处是使讨论仅限于两个窗口,也就是发送方的发送窗口和接收方的接收窗口。TCP的滑动窗口是以字节为单位的。
-
现在假设发送方收到了一个来自接收方的确认报文段,在报文段首部中的窗口字段的值为20,也就是接收方表明自己的接收窗口的尺寸为20字节,确认号字段的值为31,这表明接收方希望收到下一个数据的序号是31,而序号30为止的数据已经全部正确接收了。
-
因此发送方根据这两个字段的值,构造出自己的发送窗口。为了简单起见,我们假定网络不存在拥塞问题,也就是发送方在构造自己的发送窗口时,仅考虑接收方的接收窗口,而不考虑拥塞窗口。由于本例中接收方告诉发送方自己的接收窗口尺寸为20,因此发送方将自己的发送窗口尺寸也设置为20,发送方在没有收到接收方确认的情况下,可以把发送窗口内的数据依次全部发送出去,凡是已经发送过的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。
-
发送窗口后沿的后面部分是已发送并已收到确认的数据字节的序号,这些数据字节显然不需要再保存在发送缓存中了,可以将它们删除。发送窗口前沿的前面部分是当前不允许发送的数据字节的序号。
-
然后我们说说发送窗口前沿的移动情况和后延的移动情况。
-
其中发送窗口的前沿还可能向后收缩,这发生在接收方通知的窗口变小了,但TCP标准强烈不赞成这样做,因为很可能发送方在收到这个通知之前,就已经发送了窗口中的许多数据,现在又要收缩窗口,不让发送这些数据,显然就会产生错误。
-
现在假定发送方将发送窗口内序号31~ 41的数据,封装在几个不同的报文段中发送出去,此时发送窗口的位置并没有改变,发送窗口内序号31~41的数据已经发送,但未收到确认,而序号42 ~50的数据是允许发送,但还未发送的。请同学们思考一下,我们如何描述发送窗口的状态,换句话说,如果我们要编程实现滑动窗口机制,那么对于发送窗口的状态,应该如何标记和维护呢?如图所示可以使用三个指针,P1、P2、P3分别指向相应的字节序号,这样小于P1的,就是已发送并已收到确认的部分,大于等于P3的是不允许发送的部分。
-
我们再来看看接收方的接收窗口,它的尺寸为20,在接收窗口外面到30号为止的数据是已经发送过相应确认,并已交付给应用进程的数据,因此无需再保留这些数据,可将他们从接收缓存中删除了。接收窗口内31~ 50号数据是允许接收的数据,接收窗口外51号及其后续数据目前不允许接收。假设发送方之前发送的封装有32和33号数据的报文段到达了接收方,由于数据序号落在接收窗口内,所以接收方接受他们,并将他们存入接收缓存,但是他们是未按序到达的数据,因为31号数据还没有到达,这有可能是丢了,也有可能是滞留在网络中的某处。请注意接收方只能对按序收到的数据中的最高序号给出确认,因此接收方发出的确认报文段中的确认序号仍然是31,也就是希望收到31号数据,窗口字段的值仍是20,表明接收方没有改变自己接收窗口的大小
-
发送方收到该确认报文段后,发现这是一个针对31号数据的重复确认,就知道接收方收到了未按序到达的数据,由于这是针对31号数据的第一个重复确认因此,这并不会引起发送方针对该数据的快重传。另外接收方通知的窗口尺寸仍是20,因此发送方保持自己的发送窗口尺寸为20,现在假设封装有31号数据的报文段到达了接收方,方接受该报文段,将其封装的31号数据存入接收缓存,接收方现在可将接收到的31~33号数据交付给应用进程
-
然后将接收窗口向前移动三个序号,并给发送方发送确认报文段。该确认报文段中窗口字段的值仍为20,表明接收方没有改变自己接收窗口的大小,确认号字段的值为34,这表明接收方已经收到了序号33为止的全部数据。
-
现在假设又有几个数据报文段到达了接收方,他们封装有37 38以及40号数据,这些数据的序号虽然落在接收窗口内,但他们都是未按需到达的数据,只能先暂存在接收缓存中。假设接收方先前发送的确认报文段到达了发送方,发送方接收后,将发送窗口向前滑动三个序号,发送窗口的尺寸保持不变,这样就有新序号51~ 53落入发送窗口内,而序号31~ 33移出了发送窗口,现在可将31~33号数据从发送缓存中删除了,因为已经收到了接收方针对他们的确认
-
发送方继续将发送窗口内,序号42~53的数据封装在几个不同的报文段中发送出去,现在发送窗口内的序号已经用完了,发送方在未收到接收方发来确认的情况下,不能再发送新的数据,序号落在发送窗口内的已发送数据,如果迟迟收不到接收方的确认,则会产生超时重传。
接下来我们还要对TCP可靠传输的实现做几点补充说明:
内容小结如下:
TCP的运输连接管理
TCP的连接建立(3次握手)
-
TCP是面向连接的协议,它基于运输连接来传送TCP报文段,
-
TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。
-
TCP运输连接有以下三个阶段,
- 第一个阶段是建立TCP连接,也就是通过三报文握手来建立TCP连接。
- 第二个阶段是数据传送,也就是基于已建立的TCP连接,进行可靠的数据传输。
- 第三个阶段是释放连接,也就是在数据传输结束后,还要通过四报文挥手来释放TCP连接,
-
TCP的运输连接管理就是使运输连接的建立和释放都能正常的进行。
TCP的连接建立要解决以下三个问题:
- 第一使TCP双方能够确知对方的存在
- 第二使TCP双方能够协商一些参数,例如最大窗口值是否使用窗口扩大选项和时间戳选项以及服务质量等
- 第三使TCP双方能够对运输实体资源,例如缓存大小,连接表中的项目等进行分配
接下来我们就来看看TCP使用三报文握手建立连接的具体过程:
-
这是两台要基于TCP进行通信的主机,其中一台主机中的某个应用进程,主动发起TCP连接,建立称为TCP客户。另一台主机装被动等待TCP连接建立的应用进程,称为TCP服务器。我们可以将TCP建立连接的过程比喻为握手,握手需要在TCP客户和服务器之间交换三个TCP报文段
-
最初两端的TCP进程都处于关闭状态,一开始 TCP服务器进程首先创建传输控制块,用来存储TCP连接中的一些重要信息,例如 TCP连接表,指向发送和接收缓存的指针,指向重传队列的指针,当前发送和接收序号等。之后就要准备接受TCP客户进程的连接请求。此时TCP服务器进程就要进入监听状态,等待TCP客户进程的连接请求。TCP服务器进程是被动等待来自TCP客户进程的连接请求,而不是主动发起,因此称为被动打开连接。
-
TCP客户进程也是首先创建传输控制块,然后在打算建立TCP连接时,向TCP服务器进程发送TCP连接请求报文段,并进入同步已发送状态。TCP连接请求报文段首部中的同步位SYN被设置为1,表明这是一个TCP连接请求报文段,序号字段seq被设置了一个初始值X,作为TCP客户进程所选择的初始序号。请注意TCP规定,SYN被设置为1的报文段,不能携带数据,但要消耗掉一个序号。由于TCP连接建立是由TCP客户进程主动发起的,因此称为主动打开连接。
SYN表示synchronization,原意是同步的意思。打开就意味着客户端想和服务端进行数据的同步,在同步以后(也就是三次握手之后),客户端和服务端就可以互相发送消息。
seq表示sequence,原意为序号。需要这个seq是因为应用程序可能连续发送多个序号给服务器,有了seq就可以有依据判断哪些是累赘信息,ack搭配seq用于确认数据是否准确,是否正常通信。并且这个seq序号是随机生成的,作为初始值来进行后续的判断依据,保证了通道唯一性
-
TCP服务器进程收到TCP连接请求报文段后。如果同意建立连接,则向TCP客户进程发送TCP连接请求确认报文段,并进入同步已接收状态。该报文段首部中的同步位SYN和确认位ACK都设置为1,表明这是一个TCP连接请求确认报文段。序号字段seq被设置了一个初始值Y,作为TCP服务器进程所选择的初始序号,确认号字段ack的值被设置成了X+1,这是对TCP客户进程所选择的初始序号的确认。请注意这个报文段也不能携带数据,因为它是SYN被设置为1的报文段,但同样要消耗掉一个序号
ACK表示Acknowledgment,原意为确认。当ACK和SYN一起开启表示确认同步
小写的ack表示的确认序号,也就是说光有自己的序号seq还不够,还要有确认序号ack,这个ack是根据客户端的序号+1得到的,这样客户端在收到号码后-1就知道是不是自己发送的TCP报文了 -
TCP客户进程收到TCP连接请求确认报文段后,还要向TCP服务器进程发送一个普通的TCP确认报文段,并进入连接已建立状态。该报文段首部中的确认位ACK被设置为1,表明这是一个普通的TCP确认报文段,序号字段seq被设置为X+1,这是因为 TCP客户进程发送的第一个TCP报文段的序号为X并且不携带数据,因此第二个报文段的序号为X+1。请注意TCP规定,普通的TCP确认报文段可以携带数据,但如果不携带数据则不消耗序号。在这种情况下,所发送的下一个数据报文段的序号仍是X+1,确认号字段ack被设置为Y+1,这是对TCP服务器进程所选择的初始序号的确认。
-
TCP服务器进程收到该确认报文段后也进入连接已建立状态。现在TCP双方都进入了连接已建立状态,他们可以基于已建立好的TCP连接进行可靠的数据传输了。
想一想,为什么TCP客户进程最后还要发送一个普通的TCP确认报文段,这是否多余?换句话说,能否使用两报文握手建立连接?
答案是并不多余,不能简化为两报文握手
我们来举例说明,考虑这样一种情况:
-
TCP客户进程发出一个TCP连接请求报文段,但该报文段在某些网络节点长时间滞留了,这必然会造成该报文段的超时重传。假设重传的报文段在TCP服务器进程正常接收,TCP服务器进程给TCP客户进程发送一个TCP连接,请求确认报文段,并进入连接已建立状态。
-
请注意,由于我们改为两报文握手,因此TCP服务器进程发送完TCP连接请求确认报文段后进入的是连接已建立状态,而不像三报文握手那样进入同步已接收状态,并等待TCP客户进程发来针对TCP连接请求确认报文段的普通确认报文段。
-
TCP客户进程收到TCP连接请求确认报文段后,进入TCP连接已建立状态,但不会给TCP服务器进程发送针对该报文段的普通确认报文段,现在 TCP双方都处于连接已建立状态,他们可以相互传输数据之后可以通过四报文挥手来释放连接,TCP双方都进入了关闭状态
-
一段时间后之前滞留在网络中的失效的TCP连接请求报文段到达了TCP服务器进程,TCP服务器进程会误认为这是TCP客户进程,又发起了一个新的TCP连接请求,于是给TCP客户进程发送TCP连接请求,确认报文段,并进入连接已建立状态。该报文段到达TCP客户进程,由于TCP客户进程并没有发起新的TCP连接请求,并且处于关闭状态,因此不会理会该报文段,但TCP服务器进程已进入了连接已建立状态,他认为新的TCP连接已建立好了,并一直等待TCP客户进程发来数据,这将白白浪费TCP服务器进程所在主机的很多资源。
内容小结如下:
TCP的连接释放(4次挥手)
TCP通过四报文挥手来释放连接
我们来举例说明:
-
数据传输结束后,TCP通信双方都可以释放连接,现在TCP客户进程和TCP服务器进程都处于连接已建立状态。假设使用TCP客户进程的应用进程,通知其主动关闭TCP连接,TCP客户进程会发送TCP连接释放报文段,并进入终止等待1状态。
- 该报文段首部中的终止位FIN(Finish的缩写)和确认位ACK的值都被设置为1,表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认。序号seq字段的值设置为U它等于TCP客户进程之前已传送过的数据的最后一个字节的序号加1。
- 请注意TCP规定终止为FIN等于1的报文段,即使不携带数据也要消耗掉1个序号,确认号ack字段的值设置为v,它等于TCP客户进程之前已收到的数据的最后一个字节的序号加1。
-
TCP服务器进程收到TCP连接释放报文段后,会发送一个普通的TCP确认报文段,并进入关闭等待状态
- 该报文段首部中的确认为ACK的值,被设置为1,表明这是一个普通的TCP确认报文段,序号seq字段的值设置为V,它等于TCP服务器进程之前已传送过的数据的最后一个字节的序号加1,这也与之前收到的TCP连接释放报文段中的确认号匹配,确认号ACK字段的值设置为U+1,这是对TCP连接释放报文段的确认。
- 该报文段首部中的确认为ACK的值,被设置为1,表明这是一个普通的TCP确认报文段,序号seq字段的值设置为V,它等于TCP服务器进程之前已传送过的数据的最后一个字节的序号加1,这也与之前收到的TCP连接释放报文段中的确认号匹配,确认号ACK字段的值设置为U+1,这是对TCP连接释放报文段的确认。
-
TCP服务器进程这时应通知高层应用进程,TCP客户进程要断开与自己的TCP连接,此时从TCP客户进程到TCP服务器进程,这个方向的连接就释放了,这时的TCP连接属于半关闭状态,也就是TCP客户进程已经没有数据要发送了,但TCP服务器进程如果还有数据要发送,TCP客户进程仍要接收,也就是说从TCP服务器进程到TCP客户进程,这个方向的连接并未关闭,这个状态可能会持续一段时间,TCP客户进程收到TCP确认报文段后,就进入终止等待2状态,等待TCP服务器进程发出的TCP连接释放报文段。
-
若使用TCP服务器进程的应用进程已经没有数据要发送了,应用进程就要通知其TCP服务器进程释放连接。由于TCP连接释放是由TCP客户进程主动发起的,因此TCP服务器进程对TCP连接的释放称为被动关闭连接,TCP服务器进程发送TCP连接释放报文段,并进入最后确认状态。
- 该报文段首部中的终止位FIN和确认位ACK的值,都被设置为1,表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认。现在假定序号seq字段的值为W,这是因为在半关闭状态下,TCP服务器进程可能又发送了一些数据,确认号ACK字段的值为U+1,这是对之前收到的TCP连接释放报文段的重复确认。
- 该报文段首部中的终止位FIN和确认位ACK的值,都被设置为1,表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认。现在假定序号seq字段的值为W,这是因为在半关闭状态下,TCP服务器进程可能又发送了一些数据,确认号ACK字段的值为U+1,这是对之前收到的TCP连接释放报文段的重复确认。
-
TCP客户进程收到TCP连接释放报文段后,必须针对该报文段发送普通的TCP确认报文段,之后进入时间等待状态
- 该报文段首部中的确认为ACK的值,被设置为1,表明这是一个普通的TCP确认报文段,序号SEQ字段的值设置为U+1,这是因为TCP客户进程之前发送的TCP连接释放报文段,虽然不携带数据,但要消耗掉一个序号,确认号ACK字段的值设置为W+1,这是对所收到的TCP连接释放报文段的确认。
- 该报文段首部中的确认为ACK的值,被设置为1,表明这是一个普通的TCP确认报文段,序号SEQ字段的值设置为U+1,这是因为TCP客户进程之前发送的TCP连接释放报文段,虽然不携带数据,但要消耗掉一个序号,确认号ACK字段的值设置为W+1,这是对所收到的TCP连接释放报文段的确认。
-
TCP服务器进程收到该报文段后就要进入关闭状态,而TCP客户进程还要经过两倍的MSL后才能进入关闭状态。MSL的意思是最长报文段寿命,RFC793文档建议为两分钟
也就是说 TCP客户进程进入时间等待状态后,还要经过4分钟才能进入关闭状态,这完全是从工程上来考虑的。对于现在的网络MSL取为两分钟可能太长了,因此TCP允许不同的实现和根据具体情况使用更小的MSL值。
那么 TCP客户进程在发送完最后一个确认报文段后,为什么不直接进入关闭状态,而是要进入时间等待状态,两倍MSL后才进入关闭状态,这是否有必要呢?
来看这种情况,TCP服务器进程发送TCP连接释放报文段后进入最后确认状态,TCP客户进程收到该报文段后,发送普通的TCP确认报文段,并进入关闭状态,而不是时间等待状态。然而该TCP确认报文段丢失了,这必然会造成TCP服务器进程,对之前所发送的TCP连接释放报文段的超时重传,并仍处于最后确认状态。重传的TCP连接释放报文段到达TCP客户进程,由于TCP客户进程属于关闭状态,因此不理睬该报文段,这必然会造成 TCP服务器进程反复重传TCP连接释放报文段,并一直处于最后确认状态,而无法进入关闭状态。
因此时间等待状态以及处于该状态两倍MSL的时长,可以确保TCP服务器进程可以收到最后一个TCP确认报文段而进入关闭状态。另外TCP客户进程在发送完最后一个TCP确认报文段后,再经过两倍MSL时长,就可以使本次连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使下一个新的TCP连接中不会出现旧连接中的报文段。以上就是TCP通过4报文挥手释放连接的过程。
最后我们再来看看TCP中饱和计时器的作用。设想这样一种情况,TCP双方已经建立了连接,后来TCP客户进程所在的主机突然出现了故障,显然 TCP服务器进程以后就不能再收到TCP客户进程发来的数据,因此应当有措施使TCP服务器进程,不要再白白等待下去。换句话说,TCP服务器进程应该如何发现这种情况?
方法就是使用保活计时器。TCP服务器进程每收到一次TCP客户进程的数据,就要重新设置并启动保活计时器,若保活计时器定时周期内未收到TCP客户进程发来的数据,则当保活计时器到时后,TCP服务器进程就向TCP客户进程发送一个探测报文段,以后每隔75秒钟发送一次,若一连发送10个探测报文段,后仍无TCP客户进程的响应,TCP服务器进程就认为TCP客户进程所在主机出了故障,接着就要关闭这个连接
内容小结如下:
TCP报文段的首部格式
接下来我们就来看看TCP报文段的首部格式,TCP报文段的首部格式与IP数据报的首部格式类似,都是由二十字节的固定首部和最大四十字节的扩展首部构成。
我们首先来看源端口
和目的端口字段
:
- 源端口字段占16比特,用来写入源端口号,而源端口号用来标识发送该TCP报文段的应用进程
- 目的端口号字段占16比特,用来写入目的端口号,而目的端口号用来标识接收该TCP报文段的应用进程。
我们来举例说明源端口和目的端口的作用:
假设主机中的浏览器进程要访问WEB服务器中的WEB服务器进程,为了简单起见,我们仅从运输层端口号这个角度来举例说明,而不考虑其他细节。例如ARP、域名解析,TCP连接建立等。
-
当在浏览器地址栏中输入了外部服务器的域名后,浏览器进程会构建一个封装有HTTP请求报文的TCP报文段,该报文段首部中的源端口字段,会填写一个短暂端口号,例如49152用来标识发送该报文段的浏览器进程,目的端口字段会填写熟知端口号80,因为是用HTTP协议的WEB服务器进程,默认监听该端口
-
WEB服务器收到该TCP报文段后,从中解封出HTTP请求报文,并根据TCP报文段首部中目的端口字段的值80,将HTTP请求报文上交给WEB服务器进程,WEB服务器进程根据HTTP请求报文的内容进行相应处理,并构建一个HTTP响应报文,HTTP响应报文需要封装成TCP报文段进行发送。该报文段首部中的源端口字段,会填写熟知端口号80,用来标识发送该TCP报文段的WEB服务器进程,而目的端口字段会填写49152,这是主机中需要接收该TCP报文段的浏览器进程所对应的端口号。
-
主机收到该TCP报文段后,从中解封出HTTP响应报文,并根据TCP报文段首部装目的端口字段的值49152,将HTTP响应报文上交给浏览器进程,浏览器进程对HTTP响应报文的内容进行解析并显示。
接下来我们再来看看与TCP实现可靠传输相关的序号字段
,确认号字段
以及确认标志位ACK
。
例如这是一个TCP报文段,它有首部、数据载荷两部分构成,数据载荷中的每个字节数据都有序号,如图所示,请注意他们是字节数据的序号而不是内容。对于本例首部中序号字段应填入的10进制值为166,用来指出数据载荷的第一个字节的序号为166
我们来举例说明这三个字段的作用:
- TCP客户进程发送一个TCP报文段,该报文段首部中序号字段的取值为201,这表示该TCP报文段数据载荷的第一个字节的序号为201,假设数据载荷的长度为100字节,首部中确认号字段的取值为800,这表示TCP客户进程收到了TCP服务器进程发来的序号到799为止的全部数据,现在期望收到序号从800开始的数据,为了使确认号字段有效,首部中的确认标志位ACK的值必须设置为1。
- TCP服务器进程收到该报文段后,也给TCP客户进程发送TCP报文段,该报文段首部装序号字段的取值为800,这表示该TCP报文段数据载荷的第一个字节的序号为800,这正好与TCP客户进程的确认相匹配,假设数据载荷的长度为200字节,首部中确认号字段的取值为301,这表示TCP服务器进程收到了TCP客户进程发来的序号到300为止的全部数据,现在期望收到序号从301开始的数据,为了使确认号字段有效,首部中的确认标志为ACK的值必须设置唯一。
我们再来看数据偏移字段
:
-
TCP报文段首部中的
保留字段
占6比特,保留为今后使用,目前应至为0。 -
我们再来看看
窗口字段
:- 该字段占16比特,以字节为单位,该字段指出的是发送本报文段的一方的接收窗口,窗口值作为接收方让发送方设置其发送窗口的依据,这是以接收方的接收能力来控制发送方的发送能力,也就是所谓的流量控制,需要注意的是发送窗口的大小还取决于拥塞窗口的大小,也就是应该从接收窗口和拥塞窗口中取小者
-
TCP报文段首部中的
校验和字段
占16比特,用来检查整个TCP报文段在传输过程中是否出现了误码,与UDP类似。在计算校验和时要在TCP报文段的前面加上12字节的尾首部,具体的校验算法就不再赘述了,因为它仅仅是一种检测算法,与TCP的其他重要功能相比,检错算法并不是重点。 -
接下来我们来看
同步标志位SYN
,该标志位在TCP连接建立时用来同步序号:
- 如图所示,TCP通过三报文握手建立连接的过程,TCP客户进程发送的TCP连接请求报文段,首部中的同步标志位SYN被置1,表明这是一个TCP连接请求报文段,TCP服务器进程发送的TCP连接请求确认报文段,首部中的同步标志位SYN被置1,确认为ACK也被置1,表明这是一个TCP连接请求确认报文段。
-
再来看看
终止标志位FIN
,该标志位用来释放TCP连接:
- 如图所示,TCP通过四报文挥手释放连接的过程,不管是TCP客户进程还是TCP服务器进程,他们所发送的TCP连接释放报文段,首部中的终止标志位FIN都被置1,表明这是TCP连接释放报文段
-
首部中的
复位标志位RST
用来复位TCP连接,当RST等于1时表明TCP连接出现了异常,必须释放连接,然后再重新建立连接,RST置1还可以用来拒绝一个非法的报文段,或拒绝打开一个TCP连接 -
首部中的
推送标志位PSH
用来实现推送操作。当接收方的TCP收到该标志位为1的报文段,会尽快上交应用进程,而不必等到接收缓存都填满后再向上交付。 -
首部中的
紧急标志位URG
和紧急指针字段
用来实现紧急操作。紧急标志为URG取之为1时,紧急指针字段有效,取值为0时,紧急指针字段无效,紧急指针字段占16比特,以字节为单位,用来指明紧急数据的长度。当发送方有紧急数据时,可将紧急数据插队的发送缓存的最前面,并立刻封装到一个TCP报文段中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据,接收方收到紧急标志为1的报文段,会按照紧急指针字段的值,从报文端数据载荷部分取出紧急数据,并直接上交应用进程,而不必在接收缓存中排队。 -
TCP报文段首部除了24节的固定部分,还有最大40节的选项部分,增加选项可以增加TCP的功能。
-
由于选项的长度可变,因此还需要使用
填充字段
来确保报文段首部能被四整除。这是因为数据偏移字段,也就是首部长度字段是以四字节为单位的,如果选项的长度加上20字节固定首部的长度不能被4整除,则需要使用填充字段来确保首部能被四整除。
内容小结如下;
相关文章:
【计算机网络】运输层
文章目录运输层概述运输层端口号、复用与分用的概念UDP和TCP的对比TCP的流量控制TCP的拥塞控制TCP超时重传时间的选择TCP可靠传输的实现TCP的运输连接管理TCP的连接建立(3次握手)TCP的连接释放(4次挥手)TCP报文段的首部格式运输层概述 这里我们对运输层进行概述,之…...
20222023华为OD机试 - 基站维修工程师(Python)
基站维修工程师 题目 小王是一名基站维护工程师,负责某区域的基站维护。 某地方有 n 个基站( 1<n<10 ),已知各基站之间的距离 s( 0<s<500 ), 并且基站 x 到基站 y 的距离,与基站 y 到 基站 x 的距离并不一定会相同。 小王从基站 1 出发,途经每个基站 1 …...
21. 合并两个有序链表
题目链接:解题思路:遍历,双指针:因为两个链表有序,所以只需要依次比较两个元素的大小,然后添加到新的链表中即可first指针指向第一个链表l1,second指针指向第二个链表l2,answer保存合…...
产品经理知识体系:5.如何做好产品数据分析?
数据分析 思考 笔记 数据分析 思路 基于用户路径:用户的活动路径,操作流程等行为数据。 基于产品节点:转化率、占比 分析类型 先定性:先抛出问题、提出假设 再定量:数据验证问题、验证假设 先定性、再定量、最后得…...
详解垃圾回收算法,优缺点是什么?|金三银四系列
本文详细介绍了在 JVM 中如何判断哪些对象是需要回收的,以及不同的垃圾回收算法以及优缺点。点击上方“后端开发技术”,选择“设为星标” ,优质资源及时送达上篇文章详细介绍了 JVM 的结构以及其内存结构,需要阅读请移步。本文主要…...
Android 虚拟 A/B 详解(七) SnapshotManager 之标识文件
本文为洛奇看世界(guyongqiangx)原创,转载请注明出处。 原文链接:https://blog.csdn.net/guyongqiangx/article/details/129098176 Android 虚拟 A/B 分区《Android 虚拟 A/B 分区》系列,更新中,文章列表: Android 虚拟 A/B 详解(一) 参考资料推荐Android 虚拟 A/B 详解(二…...
LA@生成子空间@范数@衡量矩阵大小@正交化
文章目录线性组合与线性方程组生成子空间范数LpL^pLp范数向量点积用范数表示ref衡量矩阵大小特殊类型矩阵和向量对角阵向量长度性质单位向量向量单位化(正规化)正交向量正交正交向量组标准正交基正交化(schmidt)正交矩阵矩阵是正交矩阵的充要条件对称矩阵正交相似概念区分&…...
MT2012_竹鼠的白色季节
竹鼠的白色季节 #include<bits/stdc.h> #include<algorithm> using namespace std;/*思路:从小到大排序,然后依次往后遍历即可*/ int main( ) {int n,d;cin>>n>>d; int tmp;vector<int>nums;for(int i0;i<n;i){cin&…...
MySQL是什么?它有什么优势?
随着时间的推移,开源数据库在中低端应用中逐渐流行起来,占据了很大的市场份额。开源数据库具有免费使用、配置简单、稳定性好、性能优良等特点,而 MySQL 数据库正是开源数据库中的杰出代表。 开源全称为“开放源代码”。很多人认为开源软件最…...
基础篇—CSS padding(填充\内边距)解析
CSS padding(填充) CSS padding(填充)是一个简写属性,定义元素边框与元素内容之间的空间,即上下左右的内边距。 属性说明padding使用简写属性设置在一个声明中的所有填充属性padding-bottom设置元素的底部填充padding-left设置元素的左部填充padding-right设置元素的右部…...
二进制枚举
一、左移:用来将一个数的各二进制位全部左移n位,低位以0补充,高位越界后舍弃。n左移1位,n<<1,相当于2*n1左移n位,1<<n,相当于2^n二、右移:将一个数的各二进制位右移N位&…...
2|数据挖掘|聚类分析|k-means/k-均值算法
k-means算法k-means算法,也被称为k-平均或k-均值,是一种得到最广泛应用的聚类算法。算法首先随机选择k个对象,每个对象初始地代表了一个簇的平均值或中心。对剩余的每个对象根据其与各个簇中心的距离,将它赋给最近的簇。然后重新计…...
使用和制作动、静态库
文章目录什么是库?静态库打包方式使用方式生成并执行可执行程序粗暴方式优化方式动态库不一样的.o文件打包方式使用方式生成可执行程序运行可执行程序无法运行时的解决方案动静态库与动静态链接什么是库? 从一开始的helloworld,到现在熟练使…...
【Java基础】023 -- 集合进阶(List、Set、泛型、树)
目录 一、集合的体系结构 1、单列集合(Collection) 二、Collection集合 1、Collection常见方法 ①、代码实现: ②、contains方法重写equals方法示例:(idea可自动重写) 2、Collection的遍历方式(…...
面试题整理01-集合详解
文章目录前言一、集合的整体结构单列集合接口:双列集合接口:二、单列集合详解1.List接口1.1 ArrayList集合特点:扩容:添加元素遍历1.2 LinkedList集合特点:添加元素:2.Set接口2.1 HashSet集合特点ÿ…...
数据驱动的两阶段分布鲁棒(1-范数和∞-范数约束)的电热综合能源系统研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
ArcGIS网络分析之发布网络分析服务(二)
在上一篇中讲述了如何构建网络分析数据集,本篇将讲解如何发布网络分析服务。本文将使用上一篇中建立的网络数据集,下载地址在上一篇博文的最后已给出。 之前我们已经实现了基于ArcMap中的网络分析,但是仅仅支持本地是万万不够的,这里我们的目的就是将我们建好的网络分析图…...
js实现元素样式切换的基本功能
需求:用户第一次点击某些元素,改变元素的某些样式,比如背景颜色,字体颜色。用户第二次点击某些元素,恢复之前的样式。.....思路:准备一定量的div盒子,并取相同的类名<div class"box&quo…...
java 策略模式 + 工厂模式 实例
一 前言 经常听说各种设计模式,知道理论,也知道应该使用,但具体怎么用,什么时候用,使用的优点一直比较模糊,今天写一个项目中经常用到的模式,来具体理解。项目中经常用到工厂模式或者策略模式&…...
本地生成动漫风格 AI 绘画 图像|Stable Diffusion WebUI 的安装和部署教程
Stable Diffusion WebUI 的安装和部署教程1. 简介2. Windows安装环境3. 运行4. 模型下载链接5. 其他资源1. 简介 先放一张WebUI的图片生成效果图,以给大家学习的动力 :) 怎么样,有没有小小的心动?这里再补充一下&…...
华为OD机试 - 异常的打卡记录 | 备考思路,刷题要点,答疑 【新解法】
最近更新的博客 【新解法】华为OD机试 - 关联子串 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 停车场最大距离 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 任务调度 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试…...
「机器学习笔记」之深度学习基础概念(基于Pytorch)
本文以 Pytorch 为线索,介绍人工智能和深度学习相关的一些术语、概念。 关于发展历史您也可以阅读深度学习神经网络之父 Jrgen Schmidhuber 所写的《Annotated History of Modern AI and Deep Learning(现代人工智能和深度学习的注释版历史)…...
概率和似然
在日常生活中,我们经常使用这些术语。但是在统计学和机器学习上下文中使用时,有一个本质的区别。本文将用理论和例子来解释概率和似然之间的关键区别。 概率与似然 假设在一场棒球比赛中,两队的队长都被召集到场上掷硬币。获胜的队长将根据掷…...
前期软件项目评估偏差,如何有效处理?
1、重新评估制定延期计划 需要对项目进行重新评估,将新的评估方案提交项目干系人会议,开会协商一致后按照新的讨论结果制定计划,并实施执行。 软件项目评估偏差 怎么办:重新评估制定延期计划2、申请加资源 如果项目客户要求严格&a…...
Xline v0.2.0: 一个用于元数据管理的分布式KV存储
Xline是什么?我们为什么要做Xline? Xline是一个基于Curp协议的,用于管理元数据的分布式KV存储。现有的分布式KV存储大多采用Raft共识协议,需要两次RTT才能完成一次请求。当部署在单个数据中心时,节点之间的延迟较低&a…...
CompletableFuture
一、一个示例回顾Future 一些业务场景我们需要使用多线程异步执行任务,加快任务执行速度。JDK5新增了Future接口,用于描述一个异步计算的结果。虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,我们必须使用Future.get()的方式阻塞调…...
面试不到10分钟就被赶出来了,问的实在是太变态了...
干了两年外包,本来想出来正儿八经找个互联网公司上班,没想到算法死在另一家厂子。 自从加入这家外包公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到11月一纸通知,所有人不许加班,薪资…...
【C++】类与对象 (四)初始化列表 static成员 友元 内部类 匿名对象 拷贝对象时的一些编译器优化
前言 本章就是我们C中类与对象的终章了,不过本章的难度不大,都是类中一些边边角角的知识,记忆理解就行了,相信经过这么长时间的学习类与对象,你对面向对象也有了更加深的理解,最后我们学习完边边角角的一些…...
04:进阶篇 - 编译 CTK
作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 在使用 CTK 之前,首先要进行编译。但要成功编译它,并不是一件很容易的事,这不仅取决于平台、Qt 的版本,也取决于编译器,以及所使用的 IDE。 平台(Linux、Windows)Qt 版本(4.x、5.x、6.x)编译器(MS…...
SQL73 返回所有价格在 3美元到 6美元之间的产品的名称和价格
描述有表Productsprod_idprod_nameprod_pricea0011egg3a0019sockets4b0019coffee15【问题】编写 SQL 语句,返回所有价格在 3美元到 6美元之间的产品的名称(prod_name)和价格(prod_price),使用 AND操作符&am…...
坑梓网站建设咨询/长沙网站制作主要公司
方法一:删除注册表选项,变为评估模式 1.windowR打开管理 2.输入regedit后回车,则就会打开注册表编辑器 3.里面有一个cacaheId然后删掉,果断的删掉,然后重新打开即可 方法二:删除动态库文件 4.找到Beyo…...
凡客诚品是什么/seo网站优化平台
试验网站#1搜索引擎优化收录情况记录日期Yahoogooglebaidusogou每日收录每日收录增量每日收录每日收录增量每日收录每日收录增量每日收录每日收录增量2007-6-24288 333 1060 4813 2007-6-25164013523330108020481302007-6-26空间超过本月流量限制……,快到月底了…...
关掉自己做的网站/运营培训
文本编辑器有很多,图形模式下有gedit、kwrite等编辑器,文本模式下的编辑器有vi、vim(vi的增强版本)和nano。vi和vim是Linux系统中最常用的编辑器。有人曾这样的说过在世界上有三种人:一种是使用Vi的,另一种…...
建设小型网站价钱/帮我搜一下长沙做网络销售
16.0.6 现在的置换已经和以前的大不一样了。 1.海洋置换 工具架上的置换,看了一下是出了一个缓存,来存储oceanspectrum的信息, 然后在ocean surface上面 设置好对应的路径,最后直接拿一个面片渲染。 结果(chou…...
安卓app开发实验报告/seo优化技术招聘
偶然得知中国有一种火星坐标系统。其原理是这样的:保密局开发了一个系统,能将实际的坐标转换成虚拟的坐标。所有在中国销售的数字地图必须使用这个系统进行坐标转换之后方可上市。这是生产环节,这种电子地图被称为火星地图。在使用环节&#…...
wordpress 新建页面 所有文章/优化推广什么意思
题目描述 【问题描述】 Gardon 昨天给小希布置了一道作业,即根据一张由不超过 5000 的 N(3<N<100)个正整数组成的数表两两相加得到 N*(N-1)/2 个和,然后再将它们排序。例如,如果数表里含有四个数 1,3,4&#x…...