文章目录:
文章目录
概述
物理层、数据链路层以及网络层共同解决了将主机通过异构网络互联起来所面临的问题,实现了主机到主机的通信。但是实际上在计算机网络中进行通信的真正实体是位于通信两端主机中的进程。
为运行在不同主机上的应用进程提供直接的通信服务是运输层的任务,运输层协议又称为端到端协议。
运输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑、所采用的路由选择协议等),它使应用进程看见的就好像是在两个运输层实体之间有一条端到端的逻辑通信信道。
根据应用需求的不同,因特网的运输层为应用层提供了两种不同的运输协议,即面向连接的TCP和无连接的UDP。
运输层端口号、复用与分用
运行在计算机上的进程使用进程标识符PID来表示。
因特网上的计算机并不是使用统一的操作系统,不同的操作系统(Windows、Linux、Mac OS)又使用不同格式的进程标识符。
为了使运行不同操作系统的计算机应用进程之间能够进行网络通信,就必须使用统一的方法对TCP/IP体系的应用进程进行标识。
TCP/IP体系的运输层使用端口号来区分应用层的不同应用进程。其中端口号是使用16比特表示,取值范围为0 ~ 65535。
熟知端口号:0 ~ 1023,IANA把这些端口号指派给了TCP/IP体系中最重要的一些应用协议(因此在编写程序时,应当避免使用这些端口,防止发生冲突),例如:FTP使用21/20,HTTP使用80,DNS使用53。
登记端口号:1024 ~ 49151,为没有熟知端口号的应用程序使用。使用这类端口号必须在IANA按照规定的手续登记,以防止重复。如,Microsoft RDP 微软远程桌面使用的端口是3389。
短暂端口号:49152 ~ 65535,留给客户进程选择暂时使用。当服务器进程收到客户进程的报文时,就知道了客户进程所使用的动态端口号。通信结束后,这个端口号可提供给其他客户进程以后使用。
注意:端口号只具有本地意义,即端口号只是为了标识计算机应用层中的各进程,在因特网中,不同计算机中的相同端口号是没有联系的。
TCP/IP体系的应用层常用协议所使用的运输层熟知端口号
举例:在浏览器键入网址后,浏览器响应的过程
用户主机、DNS服务器、Web服务器通过交换机进行互联,三者处于同一个以太网中,它们用交换机相互连接。假设Web服务器的域名如下,并且DNS服务器记录有该域名所对应的IP地址。
当我们在浏览器的地址栏中输入Web服务器的域名
此时用户PC的DNS客户端进程会发送一个DNS查询请求报文,DNS查询请求报文需要使用运输层的UDP协议,并封装成UDP用户数据报,其首部中的源端口字段的值在短暂端口号 49151 ~ 65525 中挑选一个未被占用的端口用来表示DNS客户端进程。目的端口的值设置为DNS服务器端进程所使用的熟知端口号,其值为53
将UDP用户数据报封装在IP数据报中,通过以太网发送给DNS服务器。
当DNS服务端收到搞数据报后,从中解封出UDP用户数据报。因为UDP首部中的目的端口号为53,表明应将该UDP用户数据报的数据载荷部分——DNS查询请求报文,交付给本服务器中的DNS服务器端进程。
DNS服务器端进程解析DNS查询请求报文的内容,然后按其要求查找对应的IP地址。
之后,会给用户PC发送DNS响应报文,该响应报文仍然使用UDP协议,源端口和目的端口与查询报文恰好相反。然后将其封装在IP数据报中通过以太网发送给用户PC端
用户收到数据报后,解封出UDP用户数据报。因UDP首部中的目的端口为49152,表明应将该UDP用户数据报的数据载荷部分——DNS响应报文,交付给用户PC中的DNS客户端进程。
DNS客户端进程通过解析DNS响应报中的内容,即可知道之前所请求的Web服务器的域名所对应的IP地址。
用户PC中的HTTP客户端进程便可以向Web服务器发送HTTP请求报文。该请求报文需要使用运输层的TCP协议封装成TCP报文段。源端口仍然是在短暂端口号 49151 ~ 65525 中挑选一个未被占用的端口。目的端口设置为HTTP服务器端进程所使用的熟知端口号80。
然后将TCP报文段封装在IP数据报中,通过以太网发送给Web服务器。
Web服务器进程会解析其中的HTTP请求中的内容,并给出相对应的响应报文。其响应报文仍需要使用TCP协议,源端口和目的端口与先前的HTTP请求报文中的源端口和目的端口恰好相反。
之后将TCP报文封装在IP数据报中,通过以太网发送给用户PC。
用户PC端HTTP进程解析出响应报文中的数据后,将其通过浏览器的渲染、排版等操作,最终呈现给用户。
UDP与TCP对比
UDP与TCP是TCP/IP体系结构运输层中的两个重要协议。在使用TCP/IP体系结构的网络通信中,这两个协议的使用频率仅次于网际层的IP协议。
UDP
UDP协议为User Datagram Protocol,即用户数据报协议。
使用UDP协议的通信双方可以随时发送数据。故UDP是面向无连接的协议。
由于UDP面向无连接的特性,故其支持单播、多播以及广播。
UDP处理应用报文时,发送方的应用进程将应用层报文交付给UDP,UDP直接给应用层报文添加一个UDP首部,让其称为UDP用户数据报(忽略运输层下面的各层处理)。当接收方的UDP接收到该UDP用户数据报后,直接去除掉UDP首部,将应用层报文交付给接收方的应用进程。
即UDP对应用户进程交付下来的报文既不合并也不拆分,而是保留这些报文的边界。故UDP是面向应用报文的协议。
UDP向上层提供的是无连接不可靠传输服务,适用于IP电话、视频会议等实时应用。
UDP用户数据报首部仅有8个字节
TCP
TCP协议为Transmission Control Protocol,即传输控制协议。
使用TCP协议的通信双方必须先通过“三报文握手”建立连接,连接建立成功后再进行数据传输。当数据传输结束后,必须通过“四报文挥手”来释放其连接。故TCP是面向连接的协议。
因为TCP是面向连接的协议,故其只支持单播传输,即一对一传输。
TCP处理应用报文时,发送方的TCP把应用进程交付下来的数据块仅看作是一连串无结构的字节流。TCP并不知道这些待传输的字节流的含义,仅将其编号并将其放置在自己的发送缓存中。
然后TCP根据发送策略,从其发送缓存中提取出一定数量的字节,将其构建成TCP报文段并发送。
而接收方的TCP,一方面从所接收到的TCP报文段中取出器数据载荷部分并存储在接受缓存中,另一方面将缓存中的一些字节交付给接收方应用进程。
TCP不保证接收方应用进程所收到的数据块与发送方应用进程所发出的数据块大小相等。故TCP是面向字节流的协议。TCP协议支持全双工通信。
TCP向上层提供的是面向连接的可靠传输服务,适用于要求可靠传输的应用,例如文件传输等。
因为TCP实现可靠传输、流量控制、拥塞控制等服务,其首部自然会比较复杂。
TCP报文段首部最小20字节,最大60字节。
流量控制
日常数据传输中,我们都希望数据传输的速率能够更快一点。但是如果发送方将数据发送得过快,接收方就可能来不及接收,于是就会造成数据的丢失。
流量控制(Flow Control)就是让发送方的发送速率不能太快,让接收方来得及接收。可以利用滑动窗口机制可以很方便地在TCP连接上实现发送方的流量控制。
举例
假设A、B主机建立了TCP连接之后,B向A发送报文:我的接收窗口为400,此时主机A将自己的发送窗口大小也设置为400。后面的传输过程如图所示
假设当主机B向主机A发送了零窗口的报文段后不久,主机B的接收缓存又有了一些存储空间。主机B通知主机A,自己将接受窗口调整为300。但如果此时B的通知报文在传输过程中丢失。如果不采取一定的措施,则会陷入B一直等待A发送的数据,B也一直等待B发送非零窗口的通知的死锁场景。
为了解决这个死锁问题,TCP为每一个连接设置了一个持续计时器。只要TCP连接的一方收到对方的零窗口通知,就启动该持续计时器。若在计时器结束前为收到对方的非零通知,则发送一个零窗口探测报文,仅仅携带一字节数据,对方在确认这个探测报文段时会给出自己现在接收窗口的值。若此时的接收窗口仍然是0,则重新启动持续计时器。若接收窗口不是0,则该死锁局面将被打破。
当然,当零窗口探测报文被发出时,也会启动持续计时器,防止当零窗口探测报文丢失而产生死锁的情况。
拥塞控制
在某段时间内,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就会下降。这种情况就被叫做拥塞(congestion)。
在计算机网络中的链路容量(即带宽)、交换节点中的缓存和处理机等,都是网络的资源。
若出现拥塞而不进行控制,整个网络的吞吐量将随着输入负荷的增而下降。应当使实际的拥塞控制曲线无限接近理想的拥塞控制曲线。
拥塞控制算法
TCP有四种拥塞控制算法,分别是:慢开始、拥塞避免、快重传、快恢复。
假定现在有TCP为如下条件:
- 数据单方面发送,而另一个方向只传送确认。
- 接收方总是有足够大的缓存空间,因而发送方发送窗口的大小由网络的拥塞程度来决定。
- 以最大报文段MSS的个数为讨论问题的单位,而不是以字节的单位。
发送方维护一个叫做拥塞窗口cwnd的状态变量,其值取决于网络的拥塞程度,并且动态变化。
拥塞窗口cwnd的维护原则:只要网络没有出现拥塞,拥塞窗口就再增大一些,但只要网络出现拥塞,拥塞窗口就减少一些。
判断出现网络拥塞的依据:没有按时收到应当到达的确认报文(即发生超时重传)。
发送方将拥塞窗口作为发送窗口swnd,即 swnd = cwnd。
维护一个慢开始门限ssthresh状态变量:
- 当 cwnd < ssthresh 时,使用慢开始算法。
- 当 cwnd > ssthtresh 时,停止使用慢开始算法而改用拥塞避免算法。
- 当 cwnd = ssthresh 时,既可以使用慢开始算法,也可以使用拥塞避免算法。
慢开始(slow-start)
慢开始是指,在连接刚建立时,TCP的发送窗口大小(即允许发送的未确认数据量)以指数增长的方式增加,从而迅速利用可用的带宽。这有助于避免在网络刚开始使用时就发送大量数据导致拥塞。
假设刚开始时拥塞窗口的值为1,慢开始门限值为16。发送方最开始只能发送一个数据报文段。
当发送方接收到接收方第一个报文段的确认报文后,将拥塞窗口加一,发送两个数据报文段。当发生送收到接收方的两个报文段的确认报文时再将拥塞窗口加二。循环往复,直至拥塞窗口值等于慢开始门限值。
注意:“慢开始”是指一开始向网络中注入的报文段少,并不是指拥塞窗口cwnd增长速度缓慢。
拥塞避免(congestion avoidance)
此时拥塞窗口值已经等于慢开始门限值。之后便改用拥塞避免算法,即每个传输轮次结束后,拥塞窗口值只能线性加1,而不能像慢开始一样,每个传输轮次结束后,拥塞窗口值呈指数级增长。
随着传输轮次的增加,拥塞窗口值每轮次都线性加一。
假设在一次报文段传输的过程中,丢失了几个报文段,必然会造成发送方对这些丢失报文段进行超时重传。发送方以此来判断网络可能出现了拥塞,发送方会将慢开始门限值减小为当前拥塞窗口值的一半,并将当前拥塞窗口重置为1。
并重新执行慢开始算法。直至拥塞窗口值再次达到慢开始门限值。
后面再次转变为拥塞避免算法。
注意:“拥塞避免”并非指完全能够避免拥塞,而是指在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。
快重传(fast retransmit)
慢开始和拥塞避免算法是1988年提出的TCP拥塞控制算法。
但是有时只是极个别报文段在网络中丢失,实际上网络并没有发生拥塞。这将会导致发送方超时重传,并误认为网络发生了拥塞。发送方把拥塞窗口cwnd又设置为最小值1,并错误地启动了慢开始算法,因而降低了传输效率。
因此在1990年又添加了两个新的拥塞算法(改进TCP的性能)——快重传和快恢复。
采用快重传算法可以让发送方尽早知道发生了个别报文段的丢失。所谓的快重传就是使发送方尽快进行重传,而不是等超时重传计时器超时再重传。
- 要求接受方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认。
- 即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。
- 发送方一旦收到三个连续的重复确认,就将相应的报文段立即重传,而不是等该报文段的超时重传计时器超时再重传。
- 对于个别丢失的报文段,发送方不会出现超时重传,也就不会误认为出现了拥塞(进而降低拥塞窗口cwnd为1)。使用快重传可以将整个网络的吞吐量提升越20%
快恢复(fast recovery)
当发送方一旦收到三个重复确认,则知道现在只是丢失了个别的报文段。于是不启动慢开始算法,而是执行快恢复算法。
发送方将慢开始门限ssthresh值和拥塞窗口cwnd值调整为当前窗口的一半;开始执行拥塞避免算法。
有的快恢复实现是把快恢复开始时的拥塞窗口cwnd值再调大一些,即等于新的 ssthresh + 3 。理由如下:
既然发送方收到三个重复的确认,就表明有3个数据报文段已经离开了网络。则这三个报文段不再消耗网络资源而是停留在接收方的接收缓存中。可见现在网络中不是堆积了报文段而是减少了三个报文段,因此可以适当将拥塞窗口扩大一些。
超时重传时间选择
超时重传时间的选择是TCP最复杂的问题之一。
当超时重传时间小于往返时间RTT0,则会发生不必要的重传,使得网络符合增大。
当超时重传时间远大于往返时间RTT0,会是重传推迟的时间过长,使网络的空闲时间增大,降低了网络传输效率。
因此,超时时间RTO的值应当设置为略大于报文段往返时间RTT的值。
然而TCP下层是复杂的互联网环境,主机A所发送的报文段可能只经过一个高速率的局域网,也有可能经过多个低速率的网络,并且每个IP数据报的转发路由还可能不同。
所以不能直接使用某次测量得到的RTT样本来计算超时重传时间RTO。而是利用每次测量得到的RTT样本,计算加权平均往返时间RTTs(又称为平滑的往返时间)。
当测量到第一个往返时间时,将RTTs的值直接取为第一个RTT样本的值。
在上式中,0 <= α < 1。若 α 很接近于0,则新RTT样本对RTTs的影响不大;若 α 很接近于1,则新RTT样本对RTTs的影响较大。已经成为建议标准的RFC6298推荐的 α 值为 1 / 8,即 0.125。
用这种方法得出的加权平均往返时间RTTs就比测量出的RTT值更加平滑。
很显然,超时重传时间 RTO 应略大于加权平均往返时间 RTTs。
但是其中的往返时间RTT的测量也是比较复杂的,例如下面的两种情况:
源主机若误将确认当作是对原报文段的确认,故所计算出的RTTs和RTO就会偏大,降低了传输效率。
源主机若误将确认当作是对重传报文段的确认,则所计算出的RTTs和RTO就会偏小,导致报文段没有必要的重传,增大网络负荷。
针对出现超时重传时无法测准往返时间RTT的问题,Karn提出了一个算法:在计算加权平均往返时间RTTs时,只要报文段重传了,就不采用其往返时间RTT样本。也就是出现重传时,不重新计算RTTs,进而超时重传时间RTO也不会重新计算。
当然,这又引起了新的问题。设想出现这样的情况:报文段的时延突然增大了很多,并且之后很长一段时间都会保持这种时延。因此在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据Karn算法,不考虑重传的报文段的往返时间样本。这样,超时重传时间就无法更新。这会导致报文段反复被重传。
因此,对Karn算法进行修正:报文段每重传一次,就把超时重传时间RTO增大一些。典型的做法是将新RTO的值取为旧RTO值的2倍。
可靠传输实现
TCP基于以字节为单位的滑动窗口来实现可靠传输。
发送窗口后沿的移动情况:
- 不动(没有收到新的确认)
- 前移(收到了新的确认)
前沿移动情况:
- 通常是不断向前移动的。
- 不动
- 没有收到新的确认,对方通知的窗口大小也不变。
- 收到新确认但对方通知的窗口缩小,使发送窗口前沿正好不动。
- 向后收缩(对方通知的窗口缩小了,TCP标准强烈不赞成这样做,很可能发送方在收到这个通知之前,就已经发送了窗口中的许多数据,现在收缩窗口,不让发送这些数据,显然会出现错误)。
如上图,此时出现这种发送窗口的状态,可以进行下面的描述:
使用三个指针P1、P2、P3分别指向相应的字节序号:
小于P1的是已经发送并且已经收到确认的部分。
大于等于P3的是不允许发送的部分。
P3 - P1 = 发送窗口的尺寸;
P2 - P1 = 已发送但尚未收到确认的字节数;
P3 - P2 = 允许发送但当前尚未发送的字节数(又称为可用窗口或有效窗口)
虽然发送方的发送窗口是根据接收方的接收窗口设置的,但在同一时刻,发送方的发送窗口并不总是接收方的接收窗口一样大。
- 网络传送窗口值需要经历一定的时间滞后,并且这个时间还是不确定的。
- 发送方还可能根据网络当时的拥塞情况适当减小自己的发送窗口尺寸。
对于不按序到达的数据应如何处理,TCP并无明确规定。
- 如果接收方把不按序到达的数据一律丢弃,那么接收窗口的管理将会比较简单,但这样做对网络资源的利用不利,因为发送方会重复传送较多的数据。
- TCP通常对不按序到达的数据是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程。
TCP要求接收方必须有累积确认和捎带确认机制,这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。
- 接收方不应过分推迟发送确认,否则会导致发送方不必要的超时重传,这反而浪费了网络的资源。
TCP标准规定,确认推迟的时间不应超过0.5秒。若收到一连串具有最大长度的报文段,则必须每隔一个报文段就发送一个确认[RFC 1122] - 捎带确认实际上并不经常发生,因为大多数应用程序很少同时在两个方向上发送数据。
TCP的通信是全双工通信。通信中的每一方都在发送和接收报文段。因此,每一方都有自己的发送窗口和接收窗口。在提到这些窗口时,一定要弄清楚是哪一方的窗口。
运输连接管理
TCP是面向连接的协议,它基于运输链接来传送TCP报文段。
TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。
其中,TCP运输连接有以下三个阶段:
- 建立TCP连接
- 数据传输
- 释放TCP连接
TCP的运输连接管理就是使运输连接的建立与释放都能正常地运行。
建立连接
TCP建立连接需要解决以下三个问题:
① 使TCP双方都能够确知对方的存在。
② 使TCP双方能够协商一些参数(例如,最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)。
③ 使TCP双方能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
TCP(Transmission Control Protocol)的连接建立采用"三报文握手"过程。这个过程涉及到客户端(Client)和服务器端(Server)之间的通信。以下是TCP三次握手的详细过程:
-
客户端发起连接请求:
- 客户端首先向服务器发送一个SYN(同步)标志的TCP报文段。
- 客户端选择一个初始序列号(ISN)并将SYN标志设置为1,表示这是一个连接请求。
-
服务器响应连接请求:
- 服务器收到客户端的SYN报文段后,如果同意建立连接,就会发送一个ACK(确认)标志和SYN标志都置为1的报文段作为响应。
- 服务器也会选择一个初始序列号,这个序列号由服务器自己生成。
-
客户端确认连接:
- 客户端收到服务器的响应后,会发送一个确认报文段,其中ACK标志设置为1,表示客户端确认收到了服务器的响应。
- 这个报文段的序列号会加1,而确认号(ACK number)会设置为服务器发来的序列号加1。
至此,TCP连接就建立起来了。这个过程保证了双方都愿意建立连接,并且可以正常通信。这三次握手的目的主要有两点:
-
双方通信的能力确认: 通过三次握手,双方确认彼此具备发送和接收数据的能力。
-
初始序列号的同步: 通过握手过程,双方协商并同步了初始序列号,用于后续的数据传输。
如果只进行两次握手而不是三次握手,可能会导致一些问题,主要涉及到连接的稳定性和安全性:
-
连接的不确定性:
- 在两次握手的情况下,服务器无法确认客户端是否已经接收到连接请求,因为连接请求和确认可以在网络中延迟或丢失。
- 可能导致服务器误认为连接已建立,而客户端可能仍未准备好。
-
连接的半开状态:
- 两次握手可能导致一种情况,即连接处于半开(half-open)状态,其中一方认为连接已经建立,但另一方并不知情。
- 这种状态可能导致资源浪费或者数据传输的不确定性。
-
序列号同步问题:
- 在三次握手中,序列号的同步是通过第三个报文来实现的。在两次握手的情况下,可能存在序列号同步的问题,导致后续的数据传输混乱。
-
安全性问题:
- 缺少第三次握手可能使得连接更容易受到恶意的连接请求攻击,例如 SYN 攻击,其中攻击者可以发送大量的连接请求,占用服务器资源。
举例
当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连接的关闭是通过"四次报文挥手"来完成的。这个过程涉及到连接的一方发起关闭请求,另一方确认并同意关闭:
-
主动关闭方发起连接关闭请求:
- 主动关闭方(一般是客户端)发送一个带有FIN(结束)标志的TCP报文段,表示它已经完成了数据的发送。
- 这个报文的序列号表示数据的最后一个字节的序列号。
-
被动关闭方发出确认:
- 被动关闭方(一般是服务器)收到FIN后,会发送一个带有ACK标志的报文,表示它收到了关闭请求。
- 被动关闭方可能在发送ACK之前仍有数据需要发送,因此在这个ACK中可能包含一些数据。
-
被动关闭方发起连接关闭请求:
- 被动关闭方在准备好关闭连接时,会发送一个带有FIN标志的报文,向对方表示它也准备关闭连接。
- 这个报文的序列号也表示数据的最后一个字节的序列号。
-
主动关闭方发出确认:
- 主动关闭方收到FIN后,向被动关闭方发送一个ACK,表示它也同意关闭连接。
- 一旦这个ACK被确认,连接就正式关闭。
至此,TCP连接的四次挥手过程就完成了。这个过程确保了双方都有机会完成数据的发送,并且在双方都准备好之后关闭连接,以确保数据的完整性和可靠性。
需要注意的是,虽然这个过程中每一方都发送了FIN和ACK标志,但这并不代表每一个标志都对应一个报文,有可能多个标志被合并到一个报文中发送。这种合并有助于提高连接的效率。
其中的MSL(Maximum Segment Lifetime)是最长报文段寿命,RFC793建议是2分钟。
不过对于现在的网络状况来说,MSL设置为两分钟时间有点太长了,因此TCP允许不同的实现可根据具体情况使用更小的MSL值。
为什么TCP客户端发送完最后的TCP普通确认报文之后还要等待两个单位的MSL时间呢?
原因有以下两点:
- 保证最后发送TCP普通确认报文顺利到达TCP服务器,使得双方顺利关闭连接。
- 清理TCP传输信道上此次连接所产生的所有报文段,防止新的TCP连接中出现旧连接的报文段。
举例
假设TCP客户端发送完最后一个普通确认报文段后立马关闭连接,但该报文段在网络传输的过程中丢失了,会导致TCP服务器对最后确认报文段的超时重传,但此时的TCP客户端已经关闭,故其不会再理会此报文段,就会导致TCP服务器进程无法进入关闭状态,从而消耗大量服务器资源。
如果已经建立连接的TCP客户端与TCP服务器之间,当TCP客户端出现了故障宕机,TCP服务器是如何发现并处理的?
针对这种情况,TCP服务器内会有一个保活计时器来检测长时间没有活动的连接是否仍然有效。以防止因为网络故障或其他原因导致的连接丢失。
TCP 服务器进程每收到一次TCP客户进程的数据,就会重新设置并启动保活计时器(两小时定时)。
若保活计时器定时周期内未收到TCP客户进程发来的数据,则当保活计时器到时后,TCP服务器进程就向TCP客户进程发送一个探测报文段,以后则每隔75秒钟发送一次。若一次发送10个探测报文段后仍无TCP客户进程的响应,则TCP服务器进程就会认为TCP客户进程所在主机出现故障,接着就会关闭这个连接。
首部格式
上面提到过,为了实现可靠传输,TCP采用了面向字节流的方式。但TCP在发送数据时,是从发送缓存中取出一部分或全部字节并给其添加一个首部使之成为TCP报文段后进行发送。
一个TCP报文段由首部和数据载荷两部分构成,TCP的全部功能都体现在它首部中各字段的作用。
源端口:占16比特,写入源端口号,用来标识发送该TCP报文段的应用进程。
目的端口:占16比特,写入目的端口号,用来标识接收该TCP报文段的应用进程。
序号:占32比特,取值范围为[0 , 232 - 1],当序号增加到最后一个后,下一个序号就又回到了0。序号作用是指出本TCP报文段数据载荷的第一个字节的序号。
确认号:占32比特,取值范围为[0 , 232 - 1],当序号增加到最后一个后,下一个序号就又回到了0。指出期望收到对方下一个TCP报文段的数据载荷的第一个字节的序号,同时也是对之前收到的所有数据的确认。若确认号为n,则表明到序号n - 1为止的所有数据都已经正确接收,期望接收序号为n的数据
确认标志位ACK:取值为1时表示确认号字段才有效,取值为0时确认号字段无效。TCP规定,在连接建立后所有传送的TCP报文段都必须把ACK置为1。
数据偏移:占用4比特,并以4字节为单位。用来指出TCP报文段的数据载荷部分的起始处距离TCP报文段的起始处有多远。首部固定长度为20字节,因此数据偏移字段的最小值为(0101)2 。首部最大长度为60字节,因此数据偏移字节的最大值为(1111)2
保留:占6比特,保留为今后使用,但目前应设置为0。
窗口:占16比特,以字节为单位。指出发送本报文的一方的接收窗口。窗口值作为接收方让发送方设置其发送窗口的依据。这是以接收方的接收能力来控制发送方的发送能力,称为流量控制。窗口 = Min[接收窗口,拥塞窗口]
校验和:占16比特,检查范围包括TCP报文段的首部和数据载荷两部分。在计算校验和时,要在TCP报文段的前面加上12字节的伪首部。
同步标志位SYN:在TCP连接建立时用来同步序号。
终止标志位FIN:用来释放TCP连接。
复位标志位RST:用来复位TCP连接。当RST = 1时,表明TCP连接出现了异常,必须释放连接,然后再重新建立连接。当RST置为1时还用来拒绝一个非法的报文段或拒绝打开一个TCP连接。
推送标志位PSH:接收方的TCP收到该标志位为1的报文段会尽快上交应用进程,而不必等到接收缓存都填满后再向上交付。
紧急标志位URG:取值为1时紧急指针字段有效;取值为0时紧急指针字段无效。
紧急指针:占16比特,以字节为单位,用来指明紧急数据的长度。当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立即封装到一个TCP报文段中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据。
最大报文段长度MSS选项:TCP报文段数据载荷部分的最大长度。
窗口扩大选项:为了扩大窗口(提高吞吐率)。
时间戳选项:① 用来计算往返时间RTT ② 用于处理序号超范围的情况,又称为防止序号绕会PAWS。
选择确认选项:用来实现选择确认功能。
填充:由于选项的长度可变,因此使用填充来确保报文段首部能被4整除(因为数据偏移字段,也就是首部长度字段,是以4字节为单位的)。