从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层,但网络边缘部分的两台主机使用网络核心部分的功能进行端到端的通信时,都要使用协议栈中的运输层,而网络核心部分中的路由器在转发分组时只用到下三层的功能。
从IP层来说,通信的两端是两台主机,IP数据报的首部明确地标志了两台主机的IP地址。但真正进行通信的实体是在主机中的应用进程,是两台主机中的应用进程在进行通信。即端到端的通信是指应用进程之间的通信。
运输层有一个很重要的功能–复用(multiplexing)和分用(demultiplexing)。
复用:发送放不同的应用进程都可以使用同一运输层协议传送数据。 应用层所有的应用进程都可以通过运输层再传送到IP层
分用:接收方的运输层在剥去报文的首部后能够把这些数据正确交付目的应用进程。 运输层从IP层收到发送给各应用进程的数据后,必须分别交付指明的应用进程
UDP:用户数据报协议(User Datagram Protocol)。
TCP:传输控制协议(Transmission Control Protocol)
UDP在传送数据之前不需要先建立连接。
TCP则提供面向连接的服务。TCP不提供广播或多播服务。
UDP只在IP的数据报服务上增加了很少一点的功能,即复用和分用的功能以及差错检测的功能。
UDP的主要特点:
(1)UDP是无连接的
(2)UDP使用尽最大努力交付
(3)UDP是面向报文的
(4)UDP没有拥塞控制
(5)UDP支持一对一、一对多、多对一和多对多的交互通信
(6)UDP的首部开销小,只有8个字节,比TCP的20个字节的首部要短
TCP最主要的特点:
(1)TCP是面向连接的运输层协议
(2)每一条TCP连接只能有两个断点(endpoint),每一条TCP连接只能是点对点的
(3)TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
(4)TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。
(5)面向字节流。TCP中的流(stream)是指流入到进程或从进程流出的字节序列。
面向字节流的含义是:虽然应用进程和TCP的交互是一次一个数据块,但TCP把应用进程交下来的数据仅仅看成是一连串的无结构的字节流。
TCP的连接是逻辑连接而非真正的物理连接。
TCP把连接作为最基本的抽象
TCP连接的端点叫做套接字(socket)或插口。
根据RFC793的定义:端口号拼接到(concatenated with)IP地址即构成了套接字,因此套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。
如:IP地址为192.3.4.5,端口号为80,则得到的套接字为:(192.3.4.5:80)
即:
套接字socket=(IP地址:端口号)
每一条TCP连接唯一地被通信两端的两个端点(即套接字对socket pair)所确定。即:
TCP连接::={socket1,socket2}={(IP1:port1),(IP2:port2)}
TCP连接的端点是个很抽象的套接字,即(IP地址:端口号)。同一IP地址可以有多个不同的TCP连接,同一端口号也可以出现在多个不同的TCP连接中。
TCP报文段首部的前29个字节是固定的,后面有4n字节是根据需要而增加的选项,因此TCP首部的最小长度是20字节。
首部固定部分各字段的意义如下:
(1)源端口和目的端口:各占2个字节,分别写入源端口号和目的端口号。TCP的分用功能通过端口实现
(2)序号:也称报文段序号,占4个字节,序号范围是[0,2^32-1],序号使用mod2^32运算,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。
如:本报文段第一个字节序号301,携带数据共100字节。则本报文段最后一个字节的序号为400,下个报文段的数据序号要从401开始,下一个报文段的序号为401
(3)确认号:占4字节,期望收到对方下一个报文段的第一个数据字节的序号。
如:B收到A发来的报文段,序号为501,数据长度为200,(序号501-700),则B期望收到的下一个数据序号为701
(4)数据偏移:占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,其单位为32位字(4字节)。这个字段实际上是指出TCP报文段的首部长度。
(5)保留:占6位:保留为今后使用,目前置为0
(6)紧急URG(URGent):为1代表紧急指针字段有效
(7)确认ACK(ACKnowledgment):仅当ACK=1时确认号字段才有效,ACK为0时确认号无效
(8)推送PSH(PuSH):两个应用进程进行交互式通信时,发送方应用进程希望键入一个命令后立即能收到对方响应,则将PSH置1并创建一报文段发送出去,接收方收到PSH为1的报文段,
则尽快地交付接收应用进程,而不等待缓存填满再交付。
(9)复位RST(ReSeT):也称重建位或重置位,RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立运输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。
(10)同步SYN(SYNchronization):在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。
因此SYN置为1表示这是一个连接请求或连接接收报文
(11)终止FIN(FINish):用来释放一个连接。FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。
(12)窗口:占2字节。窗口值是[0,2^16-1]的整数。窗口指的是发送本报文段的一方的接收窗口。窗口指的是发送本报文段的一方的接收窗口。即接收方目前允许对方发送的数据量。
(13)校验和:占2字节。校验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算校验和时,要在TCP报文段的前面加上12字节的伪首部。
(14)紧急指针:占2字节。紧急指针仅在URG=1时才有效,它指出本报文段中紧急数据的字节数(紧急指针结束后就是普通数据)。即使窗口为0时也可发送紧急数据。
(15)选项:长度可变,最长可达40字节。当没有使用"选项"时,TCP的首部长度为20字节。最后的填充字段仅仅是为使整个TCP首部长度是4字节的整数倍。
选项有:最大报文段长度MSS(Maximum Segment Size)、窗口扩大、时间戳、选择确认(SACK)
TCP的滑动窗口以字节为单位。假定A收到B发来的确认报文段,其中窗口是20字节,确认号是31(表明B期望收到的下一个字节序号为31),根据这两个数据,A构造出自己的发送窗口:从31开始的连续20个字节构成的窗口。
A在发送数据时,描述发送窗口的状态需要三个指针:P1、P2、P3
P1之前的数据:已发送并收到确认的部分
P3之后的数据:不允许发送的部分
P3-P1=A的发送窗口=20(序号31-50)
P2-P1=已发送但未收到确认的字节数(31-41)
P3-P2=允许发送但还未发送的字节数(42-50)(又称可用窗口或有效窗口)
如果P2移动至与P3重合,即所有窗口数据都已发送但却没有收到B的确认,则A在经过一段时间(超时计时器控制)后会重传这些数据,再重新设置超时计时器,直到收到B的确认位置。反之如果收到B的确认,则A可以使发送窗口向前滑动,并发送新的数据。
TCP采用一种自适应算法,它记录了一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间RTT.TCP保留了RTT的一个加权平均往返时间RTTs(平滑的往返时间,S表示Smoothed)。每当第一次测量到RTT样本时,RTTs值就取为所测量到的RTT样本值,以后每测量到新的RTT样本值,就按如下公式重新计算RTTs:
RTTs=(1-α)*(旧的RTTs)+α*(新的RTT样本)
α:更新幅度
在上式中,α取接近0,则表示新RTTs值与旧RTTs值相比变化不大,接近1则新RTTs值受新RTT样本影响较大。建议标准的RFC 6298推荐的α值为1/8即0.125。
超时计时器设置的超时重传时间RTO(Retransmission Time-Out)应略大于上面得出的加权平均往返时间RTTs。RFC 6298建议使用下式计算RTO:
RTO=RTTs+4*RTTD
RTTD是RTT的偏差的加权平均值,它与RTTs和新的RTT样本之差有关。RFC 6298建议如此计算RTTD。第一次测量时,RTTD值取为测量到的RTT样本值的一半。以后的测量中,使用下式计算加权平均的RTTD:
新的RTTD=(1-β)*(旧的RTTD)+β*|RTTs-新的RTT样本|
β为小于1的系数,推荐值为1/4,即0.25
当重传一个报文段后收到了确认报文段,如何确认这是对之前发送的报文段的确认还是重传报文段的确认?
Karm提出了一个算法:
在计算加权平均RTTs时,只要报文段重传了,就不采用其往返时间样本。这样得出的加权平均RTTs和RTO就比较准确。
但这样引出了新的问题,采用Karm算法,超时重传时间无法更新,故对其进行修正(Karm修正算法):
报文段每重传一次,就把超时重传时间RTO增大一些。典型做法是取新重传时间为旧重传时间的2倍。直到不再发生重传,才根据RTO=RTTs+4*RTTD计算超时重传时间。
综上:
RTT:报文段的往返时间 RTTs:RTT的加权平均往返时间 RTO:超时重传时间 RTTD:RTT的偏差的加权平均值
第一次测量到RTT样本:
RTTs=RTT
RTTD=RTT*0.5
其余情况:
新的RTTs=(1-α)*(旧的RTTs)+α*(新的RTT样本) α建议为1/8
RTO=RTTs+4*RTTD
新的RTTD=(1-β)*(旧的RTTD)+β*(RTTs-新的RTT样本) β建议为1/4
Karm修正算法:
RTO=γ*(旧的RTO) γ建议为2
当收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,此时可以采用**选择确认(Selective ACK)**来只传送缺少的数据而不重传已经正确到达接收方的数据。
如果要使用选择确认SACK,则在TCP连接时,要在TCP首部选项加入"允许SACK"的选项。
以后在TCP报文段的首部中都增加了SACK选项,以报告收到的不连续的字节块的边界,然后发送方就不再重传这些接收方已经接收到的数据,而是发送那些不在这些字节块边界内的未接收的数据。
SACK文档并没有指明发送方应当如何相应SACK,因此大多数的实现还是重传所有未被确认的数据块。
见TCP发送窗口机制模块
TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。因此,运输连接就有三个阶段,即:连接建立、数据传送、连接释放。
主动发起连接建立的应用进程叫做客户(client),被动等待连接建立的应用进程叫做服务器(server)
TCP建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP报文段。如下图:
本图中A主动打开连接,B被动打开连接。
B的TCP服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求。服务器进程处于LISTEN(收听)状态,等待客户的连接请求,有则立即做出相应。
A的TCB客户进程也是首先创建传输控制块TCB,在打算建立TCP连接时,向B发出连接请求报文段,这时首部中的同步位SYN=1,同时选择一个初始序号seq=x。TCP规定SYN报文段不能携带数据,但要消耗一个序号。这时,TCP客户进程进入SYN-SENT(同步已发送)状态。
B收到连接请求报文段后,如同意建立连接,则向A发送确认,在确认报文段中将SYN位和ACK位都置1,确认号是ack=x+1,同时也为自己选择一个初始序号seq=y。此报文段也不能携带数据,但同样要消耗一个序号。此时TCP服务器进入SYN-RCVD(同步收到)状态。
TCP客户进程收到B的确认后,还要向B给出确认。确认报文段的ACK置1,确认号ACK=y+1,而自己的序号seq=x+1。TCP的标准规定,ACK报文段可以携带数据,但不携带数据则不消耗序号,这种情况下,下一个数据报文段的序号仍为seq=x+1,。此时,TCP连接已经建立,A进入ESTABLISHED(已建立连接)状态。
B收到A的确认后,也进入ESTABLISHED状态。
上述连接过程叫做三报文握手。B发送给A的报文段也可拆成两个报文段:确认报文段+同步报文段。这样过程就变成了四报文握手,但效果一样。
在某段时间内,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞(congestion)。
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不至于过载。拥塞控制所要做的都有一个前提,即网络能承受现有的网络负荷。拥塞控制是个全局性的过程。
相反,流量控制往往是指点到点通信量的控制,是个端到端的问题,流量控制所要做的是抑制发送端发送数据的速率,以便接收端来得及接收。
拥塞控制:路挤,发送方应放慢
流量控制:接收方窗口小,发送方应放慢
TCP进行拥塞控制的算法有四种:
慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)、快恢复(fast recovery)
发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量,发送放让自己的发送窗口等于拥塞窗口。当发送方没有按时收到对方的确认报文即出现超时时,判断网络出现了拥塞。
主机在已建立的TCP连接上开始发送数据时,从小到大逐渐诸如到网络中的数据字节,即从小到大逐渐增大拥塞窗口数值。
旧规定如下:
在刚刚开始发送报文段时,先把初始拥塞窗口cwnd设置为1至2个发送方的最大报文段SMSS(Sender Maximum Segment Size)的数值,但新的RFC 5681把初始拥塞窗口cwnd设置为不超过2至4个SMSS的数值。具体规定如下:
若SMSS>2190字节,
则设置初始拥塞窗口cwnd=2*SMSS字节,且不得超过2个报文段
若(SMSS>1095字节)且(SMSS<=2190字节),
则设置初始拥塞窗口cwnd=3*SMSS字节,且不得超过3个报文段
若SMSS<=1095字节,
则设置初始拥塞窗口cwnd=4*SMSS字节,且不得超过4个报文段
慢开始规定,在没收到一个对新的报文段的确认后,可以把拥塞窗口增加最多一个SMSS的数值。即:
拥塞窗口cwnd每次的增加量=min(N,SMSS)
N:原先未被确认的,但现在被刚收到的确认报文段所确认的字节数。
慢开始的慢,并非cwnd的增长速率慢,而是在TCP开始发送报文段时,只发送一个报文段,即设置cwnd=1,目的是试探网络的拥塞情况,然后视情况逐渐增大cwnd。
为防止拥塞窗口cwnd增长过大引起网络堵塞,还需设置一个慢开始门限ssthresh状态变量。
其用法如下:
当cwnd
当cwnd=ssthresh时,既可以使用慢开始算法,也可使用堵塞避免算法
拥塞避免算法的目的是让拥塞窗口cwnd缓慢增大:
每经过一个往返时间RTT,发送方的拥塞窗口cwnd的大小就加1,而非慢开始阶段那样加倍增长。故在拥塞避免阶段就称为"加法增大"AI(Additive Increase),表明在拥塞避免阶段,cwnd按线性规律缓慢增大,比慢开始算法的拥塞窗口增长速率缓慢得多
快重传算法可以让发送方尽早知道发生了个别报文段的丢失。快重传算法首先要求接收方不要等待自己发送数据时才进行捎带确认,而是立即发送确认,即使收到了失序的报文也要立即发出对已发送的报文段的重复确认。
如接收方收到了M1和M2后分别及时发出了确认,现假定接收方没收到M3却收到M4,本来接收方可以声明也不做,但按照快重传算法,接收方必须立即发送对M2的重复确认,以便让发送方及早知道接收方没有收到报文段M3。发送方接着发送M5和M6,接收方收到后也仍要再次发送对M2的重复确认。这样,发送方工收到接收方的4个对M2的确认,其中后3个都是重复确认。快重传算法规定,发送方只要一连收到3个重复确定,就可知道选择并未出现网络堵塞,而只是接收方少收到一个报文段M3,因而立即进行重传M3(即快重传)。使用快重传可使整个网络的吞吐量提高近20%。
当网络发生拥塞时,调整ssthresh和cwnd,然后执行慢开始算法。(ssthresh减半,cwnd=1,执行慢开始算法)
当收到3个重复确认时,调整ssthresh和cwnd,然后执行快恢复算法。(ssthresh减半,cwnd=ssthresh,执行拥塞避免算法)
在拥塞避免阶段,拥塞窗口线性增大,即加法增大AI,一旦出现超时或3个重复确认,就要把门限值设置为当前拥塞窗口值的一半,并大大减少拥塞窗口的数值。这常称为"乘法减少"MD(Multiplicative Decrease)。两者合在一起就是所谓的AIMD算法。
接收方根据自己的接收能力设定了接收方窗口rwnd,并将此窗口值写入TCP首部中的窗口字段,传送给发送方。因此,接收方窗口又称为通知窗口(advertised window),从接收方对发送方的流量控制的角度考虑,发送方的发送窗口一定不能超过对方给出的接收方窗口值rwnd。