传输层位于计算机网络体系五层结构中的第四层,它的职能是:为运行在不同主机上的进程提供直接的通信服务。
和网络层提供服务的范围差异如下图所示:
即网络层提供了主机到主机间的通信(如果是IP协议的话还是不可靠的通信),而传输层提供的是主机中的进程与进程之间的通信(TCP协议提供可靠传输,UDP协议提供不可靠传输)。
更加直观的示意图如下所示:
为了使运行不同操作系统的计算机的应用进程之间能够进行网络通信,就必须使用统一的方法对TCP/IP体系的应用进程进行标识。
这里用于标识不同应用进程的东西就是端口号:
端口号分类:
熟知端口号 | 登记端口号 | 短暂端口号 |
---|---|---|
熟知端口号: 0~1023, IANA把这些端口号指派给了TCP/IP体系中最重要的一些应用协议,例如: FTP使用21/20,HTTP使用80,DNS使用53。 | 1024~49151, 为没有熟知端口号的应用程序使用。使用这类端口号必须在IANA按照规定的手续登记,以防止重复。例如:Microsoft RDP微软远程桌面使用的端口是3389。 | 49152~65535, 留给客户进程选择暂时使用。当服务器进程收到客户进程的报文时,就知道了客户进程所使用的动态端口号。通信结束后,这个端口号可供其他客户进程以后使用。 |
TCP/IP体系结构应用层常用协议所使用的运输层熟知端口号:
UDP和TCP是计算机网络层的两个重要协议,如下图所示:
UDP协议是无连接的,TCP协议是面向连接的,如下所示:
UDP | TCP |
---|---|
|
|
之所以TCP需要面向字节流,是因为TCP需要实现可靠传输、流量控制和拥塞控制,面向字节流是实现上述技术的基础。
UDP | TCP |
---|---|
|
|
因为TCP需要实现的功能较为复杂,因此TCP报文段的首部要比UDP数据包的首部大得多。
一般情况下,我们都是希望信息可以尽快传输,但如果是TCP连接一对一进行传输时,如果不进行流量控制,就会出现一方传输速度过快,导致另一方的接收信息的缓存满了,如果再继续发送信息只会导致这部分信息的丢失,然后需要进行信息重传等操作,进而不仅信息传输比原来要慢很多,还占用了很多额外的网络资源。
TCP协议采用了滑动窗口的机制来进行流量控制。
发送窗口和接收窗口
逻辑上,发送端有一个控制发送数据量的窗口,称为发送窗口,当发送端将发送窗口中的所有数据都发送出去后,还没有收到接收端的应答之前,都不能进行下一步的操作,例如移动窗口,发送新数据等等。
而接收窗口相当于接收端当前可以接受数据量的大小。
发送窗口的大小由接收端(接收窗口大小)来决定,这是保证流量控制,保证数据不溢出的关键。
当前接收方发送的rwnd为0,即接受窗口的大小为0,所以发送窗口也被调控为0,因而发送方无法继续发送数据。
考虑当接收方又出现了一定的接收空间,然后将当前的rwnd发送到发送方,但此时这个报文段丢失了,那么发送端无法接收到rwnd的变化信息,因而又无法发送数据,此时就会造成双方都在等待对方相应的状况,即死锁,如下图所示:
其实这种情况下,即发送方接收到rwnd=0
的信息后会启动持续计时器,当这个阶段还未接收到接收端发来的信息时就会发送零窗口探测报文进行询问,以打破死锁局面:
疑问1:零窗口探测报文如果丢失了怎么处理?回答:零窗口探测报文也有超时重传计时器,保证可以不断发送探测报文
疑问2:如果接收窗口为0如何接收零窗口探测报文?回答:TCP规定这种特殊情况的报文接收端也必须有机制进行接收
例题:
包括四个子算法:
为了实现拥塞控制,发送方除了需要维护swnd(发送窗口)之外,还需要额外维护一个新的变量cwnd(拥塞窗口),它的值取决于拥塞程度,而且动态变化。
此时,swnd = min(rwnd, cwnd)
,即发送窗口的大小应为接收窗口和拥塞窗口的最小值,进而同时实现流量控制和拥塞控制。
cwnd的变化规律:
网络没有出现拥塞时,cwnd再增大一些
一旦出现拥塞,cwnd就要减小一些
判断网络是否发生拥塞的依据:
重传定时器超时
收到三个相同(重复)的 ACK
其实这两个依据的本质都是相同的,即发出的报文段丢失了。
最后,为了cwnd的增大变化更加合理,在特定的情况下采用特定的算法进行增大,发送端还需要维护一个慢开始门限变量ssthresh状态变量:
为了能够更简单地说明问题,假定如下条件:
连接成功后,假设发送端的拥塞窗口值被设置为1,此外还需要设置慢开始门限的初始值,这里以16为例。
慢开始算法:每次收到一个ACK,cwnd += 1。
具体案例如下所示:
因此在理想情况下运行慢开始算法时是每接收到一轮回复时cwnd *= 2
,我们在做题时往往是考虑这样的理想情况的。
拥塞窗口的大小随传输轮次的增大的变化如下图所示:
当cwnd达到ssthresh(慢开始门限)时,就会转而运行拥塞避免算法,即:每收到一个新的ACK,将CWND += MSS / CWND
在理想条件下,若每个ACK都没有延迟,则在每个RTT之后,cwnd的变化相当于cwnd += 1
。
当出现某报文段发生超时重传时,判断网络发生了拥塞,此时进行如下操作:
即步骤为:
ssthresh /= 2; cwnd = 1;
,然后转1继续运行按照以上步骤执行直到信息发送完全为止。
因而总的流程如下图所示:
tips:
慢开始和拥塞避免算法是1988年提出的TCP拥塞控制算法(TCP Tahoe版本)。
1990年又增加了两个新的拥塞控制算法(改进TCP的性能),这就是快重传和快恢复(TCP Reno版本)。
原因:有时,个别报文段会在网络中丢失,但实际上网络并未发生拥塞。这将导致发送方超时重传,并误认为网络发生了拥塞,进而发送方把拥塞窗口cwnd又设置为最小值1,并错误地启动慢开始算法,因而降低了传输效率。
执行快重传算法的过程如下:
即使用这个算法可以减少发送端对网络拥塞的误判,使发送端更早地对丢失报文段进行重传,进而提高传输效率。
下图的传输过程包括了四种算法的使用:
TCP Reno版本的拥塞控制如下:
可见,RTO太小或太大都不合适,太小时会使网络符合增大,太大时会降低传输速率。
因此,一般我们会取一个比往返时间RTT稍大的值作为RTO的值,如下图所示:
要计算RTO,首先我们需要先计算加权平均往返时间RTTS,计算公式为:
即新的RTTS由新的RTT样本和旧的RTTS同时决定,里面α的取值确定了两者的重要性,根据标准一般取值为1/8,即旧的RTTS权重较大:
而RTO的大小要略大于RTTS,其完整的计算公式如下:
RTTS的计算过程已经提到过了,即:
而RTTD的计算如下:
按道理我们已经可以计算每一传输轮次的RTTS了,但是实际上还是会出现问题,这里主要是RTT样本在发生重传时很可能出现偏差,如下图所示:
因此我们需要解决这种网络不可靠情况下的RTT测量问题,这里主要是使用Karn算法:
在计算RTTS的过程中,只要报文段进行了重传,就不采用该报文传输得到的RTT样本。(样本重传不采用)
但这样也会出现特殊情况无法更新RTO:报文段的时延突然增大了很多,并且之后很长一段时间都会保持这种时延。因此在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据Karn算法,不考虑重传的报文段的往返时间样本。这样,超时重传时间就无法更新。这会导致报文段反复被重传。
因此我们使用修正后的Karn算法:报文段每重传一次,就把超时重传时间RTO增大一些。典型的做法是将新RTO的值取为旧RTO值的2倍。(RTO *= 2
)
以下是一个计算的例子:
总的计算方法如下图所示:
TCP基于以字节为单位的滑动窗口来实现可靠传输。
滑动窗口示意图如下所示:
实现上维护3个指针来描述发送窗口的状态:
具体的报文段发送过程如下所示:
例1:
例2:
TCP是面向连接的协议,它基于运输连接来传送TCP报文段。因此TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。
首先TCP服务器自身先建立相应的传输控制块,内容如下,并进入监听状态,等待TCP客户进程的连接请求:
然后TCP客户端发送TCP连接请求 SYN = 1, seq = x
,SYN设置为1代表这是一个连接请求,且TCP规定当SYN设置为1的报文段不能携带数据,并要消耗掉一个序号seq,示意图如下:
当TCP服务器接收到该请求后,会发送一个TCP连接请求的确认,SYN = 1, ACK = 1
代表这是对连接请求的确认,而 ack = x+1
表示对收到的请求报文的应答。同理,这个报文段也不能携带数据并要消耗掉一个序号seq。
最后TCP客户端接收到服务器的确认后还需再发送一个报文段进行应答,至TCP服务器接收到该报文后,连接正式建立:
三报文握手能否简化成两报文?
不能,一个简单的考量是:
但如果不再发送一个额外的请求则无法证明客户端可以接受数据,因而无法保证连接的可靠性。
另外特殊的情况如下图所示:
TCP通过“四报文挥手”释放连接。客户端和服务器都可以发起释放连接请求。
这里假设TCP客户端主动发起释放连接请求:
其中 FIN = 1
表示这是释放连接请求报文段,另外ACK = 1, ack = v
为对前面接收到的报文段进行确认,同理,释放连接请求也需要消耗掉一个序号seq = u
。
然后TCP服务器发送一个释放连接的确认报文,并通知应用进程,至此TCP客户到服务器的单向传输就关闭了:
此时TCP连接处于半关闭状态,即客户到服务器的连接断开,但服务器到客户的连接仍继续,服务器还可以继续向客户端发送数据:
当服务器要发送的数据也发送结束后,则服务器端也会发送一个释放服务器到客户端方向连接的请求,和客户端发送的释放请求的过程基本一致:
而客户端接收到释放请求时发送释放确认,并在等待2MSL后关闭连接,而服务器接收到该确认后直接关闭连接:
最后的这个等待时间是为了防止发生这种情况:
此外当连接过程中客户端出现故障时有这样的处理方案:
整体格式如下图所示:
几个标志位:
URG和紧急指针:
紧急标志位URG:取值为1时紧急指针字段有效;取值为0时紧急指针字段无效。
紧急指针:占16比特,以字节为单位,用来指明紧急数据的长度。
当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立刻封装到一个TCP报文段中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据。
选项部分:
以上就是TCP报文首部各字段的详细含义。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.cnblogs.com/CodeReaper/p/15885285.html
内容来源于网络,如有侵权,请联系作者删除!