TCP协议最主要的特点
- TCP是面向连接的运输层协议。这就是说,应用程序在使用TCP协议之前,必须要建立TCP连接,且在传输完毕后,还要断开连接。
- 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点(一对一),并且按序到达。
- TCP提供全双工通信。TCP允许通信双方的应用进程可以在任何时候都能发送时数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送的时候,应用进程把数据传送给TCP缓存后,就可以做自己的事情,而TCP会在合适的时候把数据发送出去。在接受时,TCP把接受到的数据放入缓存,上层的应用进程会在合适的时候读取缓存中的数据。
- 面向字节流,TCP中的”流“指的是流入到进程或者从进程流出的字节序列。”面向字节流“的含义是:虽然应用进程和TCP交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据仅仅看成一连串的”无结构的字节流“。TCP并不知道所传送的字节流的含义。
- 如图TCP连接是一条虚连接:并不是真正的物理连接。TCP报文段先要传送到IP层,加上IP首部,再传送到数据链路层。再加上数据链路层的首部和尾部,才离开主机发送到物联链路。
TCP的连接
TCP把连接作为最基本的抽象,TCP许多的特性都与TCP面向连接相关。每一条TCP连接有两个端点,TCP连接的端点,不是主机,不是主机IP,不是应用进程,也不是运输层的协议端口,而是叫做套接字(socket)或者插口,根据RFC793规定:端口号拼接到IP地址即构成了套接字==》套接字socket=(IP地址:port端口号)。
每一条TCP连接唯一地址通信的两端(及两个套接字所规定):
TCP连接::={socket1,socket2}={(IP1:Port1),(IP2:Port2)}
可靠传输的工作原理
我们知道,TCP发送报文的时候是交给IP层,但是IP层只能提供尽最大努力服务,也就是说,TCP下面的网络层提供的是不可靠传输,因此TCP就必须采取适当的措施要使得两个运输层之间通信变得可靠。
理想的传输条件有以下两个特点:
1. 传输信道不产生差错。 2. 不管发送方以多块的数据发送数据,接受方总能及时的来处理这些数据。然而实际的网络并不具备以上两个理想条件,但我们可以采用一些可靠传输协议,当出现差错的时候让发送方重传发送错误的数据,同时在接收方来不及处理的时候及时报告发送方适当降低发送数据的速度。这样一i来,本来不可靠的传输信道就能够实现可靠传输了。下面从最简单的停止等待协议说起。
停止等待下协议
全双工通信的双方既是发送方也是接收方,下面是我们仅考虑A发送数据而B接收数据并发送确认。因此A叫做发送方,B叫做接收方。
- 无差错情况
- A发送分组M1,发送完就暂停发送,等待B的确认。B接收到M1就向就向A发送确认。A在接收到对M1确认的后,就再发送下一个分组M2。一次类推。
- 出现差错
- B接收到M1时检测到了差错,就丢弃M1,其他什么也不做(并不会通知A收到有差错的分组)。也可能是M1在传输的过程中丢失了,这时候B当然什么也不知道。在这两种情况下,B都不会发送任何信息。可靠传输协议是这样设计的:A只要超过了一段时间仍然没有接收到确认,就认为刚才发送的分组丢失了,因而重传钱前面发送过的分。这就叫做‘重传’。要实现如何重传,就要在每发完一份分组,就设置一个超时计时器,如果在规定的时间内收到对方的确认,就撤销已设置的超时计时器
其实在图5-10(a)中,A为每一个已发送的分组都设置了一个超时计时器,但A在超时计时器之前都收到了相应的确认,就撤销该超时计时器。这里应该注意三点:
- A在发送完一个分组后,还必须要保留一个已经发送分组的副本(在发送重传的时候使用),只有在接收到相应的确认后才能清楚暂时保留分分组副本。
- 分组和确认分组就必须要进行编号,这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认。
- 超时计时器设置的重传时间应该比数据在分组传输的平均往返时间要长一些,如图5-9(b)中的一条虚线标识如果如果M1正到达B处同时A也正确的收到确认报文的过程,可见重传时间也应该比平均往返时间更长一些,显然,如果重传时间设定特别的长,那么通信的效率就会很低,但如果重传的设置的太短,以致产生不必要的重传,就浪费了网络资源。关于重传时间如何处理和选择,我们会在后面讨论。
- 确认丢失和确认迟到:图5-10(a)说明的是另一种情况,B发送的对M1分组确认丢失了,A在设定的超时重传时间内没有收到确认,并无法知道是自己发出的分组错误,丢失,还是B发送的确认丢失了。因此A在超时计时器到后期就要重传M1分组。现在应该注意到B的动作。假如B接收到了重传的分组M1,这时候应该采取两个行动:
- 丢弃这个重复的分组M1,不向上层交付。
- 向A发送确认,就算是重传报文M1,也要发送确认报文。
通常情况下A最终总是能可以收到所有发出分组确认,如果A不断重传分组但总是收不到确认,说明这条通信线路太差了,不能进行通信。
使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信。
像上述的这种可靠传输协议称之为自动重传请求ARQ(Automatic Respeat ReQuest),意思是重传的请求是自动进行的,接收方不需要请求发送方重传某个出错的分组。
信道利用率
停止等待的协议优点是简单,但缺点是信道利用率太低了,我么可以用图5-11来说明这个问题
假定A发送分组需要的时间是TD。显然,TD等于分组长度除以数据率。再假定分组确认到达B后,B处理分组的时间可以忽略不计,同时立即发送一个确认。假定B发送一个确认分组需要时间为TA,如果A确认处理分组的时间也忽略不计,那么A在经过时间(TD+RTT+TA)后就可以在发送下一个分组,RTT是往返时间,因此信道的利用率U=TD/(TD+RTT+TA).
举个例子,假定1200km 的信道往返时间为RTT=20ms。分组长度为1200bit,发送速率为1M/S,则可以计算出信道利用率U=5.66%,若把发送速率提高到10B/S,则U=5.96X10^-4,信道在大多数时间都是空闲的。
因此,为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输,(如图5-12)
流水线传输就是发送方可以连续发送多个分组,不必没发完一个分组就停止等待对迪阿敏确认,这样可以使信道上的一直有数据不间断的发送,显然这种传输效率可以得到很大的提高。
当使用流水线传输时候,就要介绍下面要使用的连接ARQ协议,滑动窗口协议
连续ARQ协议
滑动窗口协议比较复杂,是TCP协议的精髓所在,
图5-13(a)表示发送方维持的发送窗口,它的意义是:位于发送窗口内的5个分组都可以连续发出去,而不需要等待对方确认,这样,信道的利用率就高了。
连续ARQ协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。图5-13(b)表示发送方接收到了对第一个分组的确认,于是把发送窗口向前移动一个分组的位置。
接收方一般采用的是累计确认的方式。这就是说,接收方不必对接收到的分组逐个发送确认。而是收到几个分组后,对按照顺序到达最后一个分组发送确认,这就表明:到这个分组为止的所有分组都正确的收到了。
TCP报文段的首部格式
TCP虽然是面向字节流的,但TCP传送的数据单元却是报文段。一个TCP报文段分为首部和数据两部分,而TCP的全部功能都体现在它在首部中各字段的作用。
TCP报文首部前20字节是固定的,后面4n字节是根据需要而增加的选项。(TCP协议首部的最小长度为20字节)
- 源端口和目的端口 (各占2字节):分别写入源端口号和目的端口号。
- 序号(4字节):序号的范围是【0,(232)-1】,共232个序号,在一个TCP连接中传送的字节流的每一个字节按照顺序编号,这个字节也叫做报文段序号。
- 确认号(4字节):是期望收到对方的下一个报文段的第一个数据字节的序号,例如:B正确的接收到了A发送过来的一个报文段,其序列号字段为501,而数据长度是200字节(序号为501-700),这表明B正确的接收到了A发送的到序号700为止的数据,。因此,B希望收到A下一个数据序号为701的数据,于是A在A发送给A确认号设置为701。总之就是要记住:确认号=N:到序号N-1为止的所有数据都已正常的收到了。
- 数据偏移(4位):它指出的TCP报文段的数据部分的其实部分距离TCP报文段的起始位置,其实就是指出了TCP报文段首部的长度,(TCP报文首部最大的长度为60字节)。
- 保留位(6位):保留为今后使用,目前是0。
- 下面是6个控制位
- 紧急URG(URGent):当URG=1,表示紧急指针字段有效,它告诉系统此报文段中有紧急数据,应该尽快送达,不要按照原来的排队顺序来传送,发送方TCP就要把这个紧急报文插入到本报文队列中的首部。
- 确认ACK(ACKnowledment)仅当ACK=1时候确认号字段才有效,当ACK=0时候,确认号无效。TCP规定,在连接建立后,所有传送的报文段都必须把ACK设置为1
- 推送PSH(PuSH)当两个应用进程进行交互式的通信的时候,有时在一端的应用进程希望在键入一个命令后能够立即接受到对方的响应。在这种情况下,TCP就可以使用推送操作。当发送方把PDSH设置为1,并立即创建一个报文段发送出去,接收方TCP收到PSH=1的报文的时候,会把这个报文尽快 的交给付给应用进程。而并不是放到缓存中。
- 复位RST(ReSet):当RST=1时候,表明TCP连接中出现了严重的差错,必须要释放连接,然后重新建立运输连接,RST=1还用来拒绝一个非法的报文段或者拒绝打开一个链接。
- 同步SYN(SYNchronization)在建立一个用来同步序号,当SYN=1而ACK=0,表明这是一个连接请求报文段,对方若同意建立连接,则应该在相应的报文段中使得SYV=1和ACK=1
- 终止FIN(FINis)用来释放一个连接,当FIN=1时,表示此报文段的发送方发送的数据已经发送完毕,并要求释放运输层连接。
- 窗口(2字节):窗口值为【0,(2^16)-1】,窗口指的是发送本报文的一方的接收窗口。窗口值告诉对方:从本报文段的确认号开始,接收方目前只能接受对方的数据报文发送量。设置这个窗口值的原因是接收方的数据接收缓存是有限的。
- 检验和(2字节):检验和字段检验的范围包括首部和数据两部分。和UDP一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部,伪首部的格式和UDP伪首部的格式一样。但应该要把伪首部的第四个字段值改为6(TCP的协议号为6),第5字段中UDP长度改为TCP长度。
- 紧急指针(2字节):紧急指针仅仅在URG=1的时候才有意义,它指出本报文段的紧急数据的字节数(紧急数据结束后就是普通数据),窗口期为0也是可以发送紧急数据。
- 选项(可变,最长为40字节)
TCP可靠传输的实现
- 以字节为单位的滑动窗口
TCP的滑动窗口是以字节为单位的,现假定A收到了B发来的确认报文段,其中窗口是20字节,而确认号是31(这表明B期望接收到的下一个序列号为31,而序号30为止的数据已经接收到了),根据这两个数据,A就构造出了自己的发送窗口。
我们首先讨论发送发A的发送窗口,发送窗口表示:在没有收到B确认的情况下,A可以连续的把窗口内的数据都发送出去。凡是已经发送出去的数据,在未收到确认之前都必须暂时保留,以便在重传时使用。
发送窗口里面的序号表示允许发送的序号,显然,窗口越大,发送方就可以在收到对方确认之前发送的数据就越多,因此就可以提高传输速率。
发送窗口后延部分表示已经已经发送且收到了确认。这些数据显然不在需要保留了,发送窗口前沿的部分表示不允许发送,因为接收方还没有为这部分数据提供缓存空间。
发送窗口的位置由窗口前沿和后延位置共同确认,
- TCP缓存和窗口的关系
发送方的应用进程把字节流写入了TCP的发送缓存中,接收方的应用进程从TCP的接收缓存中读取字节流数据。下面我们就讨论窗口和缓存之间的关系:
这里首先明确两点:
- 缓存空间和序号空间都是有限的,并且是循环使用的。
- 由于实际的缓存或窗口中的字节数是非常大的。图中只是说明一下情况。
我们首先查看一下(a)发送方的情况:
- 发送缓存用来暂时存放:
- 发送应用程序传给发送方TCP准备发送的数据。
- TCP已发出但尚未收到确认的数据。
- 发送窗口只是发送缓存的一部分,已被确认的数据应当从缓存中被删除。因此发送缓存和发送窗口的后延是重合的。发送应用程序最后写入发送缓存的字节减去最后被确认的字节,就是还保留在发送传中的被写入的字节数。发送应用进程必须控制写入缓存中的速度。不能太快,否则发送缓存就没有存放数据的空间。
再看一下图(b)接收方的情况。
- 节后缓存暂时用来存放:
- 按序到达,但尚未被应用进程接读取的数据。
- 为按序到达的数据。
- 如果收到的分组有差错,则要丢弃 。如果接受应用进程来不及读取收到的数据,接收缓存中就会被填满,使得减少到0。反之,如果接受应用程序接收到数据能够及时从接受缓存中读取到数据,接收窗口就可以不断增大,但最大就不能超过接收缓存的大小。图(b)还指出了下一个期待收到的字节号,这个字节号也是接收方给发送方的报文段中的首部确认号。
根据以上总结出:
- 虽然A的发送窗口是根据B接受窗口的大小而动态设置的,但是在同一时刻,A发送窗口和B的接受窗口并不是一样大的。这是因为通过网络传输需要经历一定的时间滞后(延迟),除此之外,发送方还要根据当时的网络环境要适当的调整自己的发送窗口。
- 对于不按序到达的数据(字节流),TCP标准并无明确规定,如果接受方把不按序的数据一律丢掉,那么接收窗口的管理就会简单很多,但是这回对网络资源的利用不利(因为发送方会不断的传送较多的数据)。因此TCP通常会把不按序到达的数据先临时放到存储窗口中,等到字节流所缺少的字节接收到后,再按序交付上层的应用进程。
- TCP要求接收方必须有积累确认的功能,这样可以减少传输开销,接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息捎上。但是这里注意:
- 一十接收方不应该过分推迟发送确认,否则这样容易导致发送方不必要的重传,这样反而浪费了网络资源。TCP规定,确认推迟的时间不能超过0.5秒,若收到了一连串具有最大长度的报文,则必须每隔一个报文段就发送一个确认【RFC 1122】.
- 二是捎带确认实际上并不是经常发生,因为大多数应用很少同时在两个方向上传输数据。
- 最后强调:TCP通信是全双工通信。通信中的每一方都在发送和接受报文段,因此,每一方都有自己的发送窗口和接收窗口。在谈到这些窗口的时候,一定要分清楚。