《计算机网络-第7版-谢希仁》学习笔记:运输层
三、运输层
1、运输层协议概述
1)、进程之间的通信
运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络的边缘部分中的两台主机使用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到了下三层的功能
真正进行通信的实体是在主机中的进程,是一台主机中的进程和另一台主机中的进程在交换数据,严格来讲,两台主机进行通信就是两台主机中的应用进程互相通信
复用:在发送方不同的应用进程都可以使用同一个运输层协议传送数据
分用:接收方的运输层在剥去报文的首部后能够把这些数据正确交付目的应用进程
网络层与运输层的区别:网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信
运输层向高层用户屏蔽了下面网络核心的细节,它使应用进程看到的就是好像在两个运输层实体之间有一条端到端的逻辑通信信道
2)、运输层的两个主要协议
UDP:在传送数据之前不需要先建立连接,远地主机收到UDP报文后,不需要给出确认,UDP不提供可靠交付,但某些情况却是最有效的工作方式
TCP:提供面向连接的服务,在传送数据前先建立连接,数据传送结束后要释放连接;TCP不提供广播或多播服务;TCP提供可靠的、面向连接的运输服务,因此增加了很多开销
3)、运输层的端口
协议端口号:虽然通信的终点是应用进程,但只要把报文交到目的主机的某个目的端口,剩下的工作就由TCP或UDP来完成
2、用户数据报协议UDP
1)、UDP概述
1)UDP是无连接的,即发送数据之前不需要建立连接,减少了开销和发送数据之前的时延
2)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表
3)UDP是面向报文的。应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文;在接收方的UDP,对IP层交上来的UDP用户数据报,在去除首部后就原封不动地交付上层的应用进程。也就是说,UDP一次交付一个完整的报文。因此,应用程序必须选择合适大小的报文。若报文太长,UDP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率
4)UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低
5)UDP支持一对一、一对多、多对一和多对多的交互通信
6)UDP的首部开销小,只有8个字节,比TCP的20个字节的首部要短
2)、UDP的首部格式
1)源端口:源端口号。在需要对方回信时选用;不需要时用全0
2)目的端口:目的端口号。在终点交付报文时必须使用
3)长度:UDP用户数据报的长度,最小值是8(仅有首部)
4)校验和:检测UDP用户数据报在传输过程中是否有错。有就丢弃
计算UDP校验和:与IP首部检验相似,但UDP的检验和把首部和数据部分一起都检验
3、传输控制协议TCP概述
1)、TCP最主要的特点
1)TCP是面向连接的运输层协议。应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接
2)每一条TCP连接只能是点对点的
3)TCP提供可靠交付的服务。通过TCP拦截传送的数据,无差错、不丢失、不重复,并且按序到达
4)TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据
5)面向字节流。流指的是流入到进程或从进程流出的字节序列;TCP把应用程序交下来的数据仅看作一串无结构的字节流
TCP连接是一条虚连接(逻辑连接),并不是真正的物理连接
2)、TCP的连接
TCP连接的端点叫做套接字,端口号拼接到IP地址即构成了套接字
每一条TCP连接唯一地被通信两端的两个套接字所确定
4、可靠传输的工作原理
1)、停止等待协议
1)无差错情况
A发送分组M1,发完就暂停发送,等待B的确认。B收到M1就向A发送确认。A在受到了对M1的确认后,就再发送下一个分组M2。同样,在收到B对M2的确认后,再发送M3
2)超时重传
要实现超时重传,就要在每发送完一个分组时设置一个超时计时器。如果在超时计时器到期之前收到了对方的确认,就撤销已设置的超时计时器
- A在发送完一个分组后,必须暂时保留已发送的分组的副本(在发生超时重传时使用),只有在收到相应的确认后才能清除暂时保留的分组副本
- 分组和确认分组都必须进行编号。这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认
- 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些
3)确认丢失
B所发送的对M1的确认丢失了。A在设定的超时重传时间内没有收到确认,或者是B发送的确认丢失了。因此A在超时计时器到期后就要重传M1。假定B又收到了重传的分组M1。这时应采取两个行动
- 丢弃这个重复的分组M1,不向上层交付
- 向A发送确认。不能认为已经发送过确认就不再发送,因为A之所以重传M1就表示A没有收到对M1的确认
4)确认迟到
传输过程中没有出现差错,但B对分组M1的确认迟到了。A会收到重复的确认。对重复的确认收下后就丢弃。B仍然会收到重复M1,并且同样要丢弃重复的M1,并重传确认分组
使用上述的确认和重传机制,可以在不可靠的传输网络上实现可靠的通信,上述这种可靠传输协议称为自动重传请求ARQ
5)信道利用率
停止等待协议的优点是简单,但缺点是信道利用率太低
信道的利用率U可用下式计算:
发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。由于信道上一直有数据不断地传送,这种传输方式可获得很高的信道利用率
2)、连续ARQ协议
发送方维持发送窗口,位于发送窗口内的分组都可以连续发送出去,而不需要等待对方确认,这样信道利用率就提高了
发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置
接收方采用累积确认的方式,在收到几个分组后,对按序到达的最后一个分组发送确认
5、TCP报文段的首部格式
1)源端口和目的端口:各占2字节,分别是源端口号和目的端口号
2)序号:占4字节,TCP中传输的数据流中的每一字节都有一个编号。序号字段的值是本报文段所发送的数据的第一个字节的序号
3)确认号:占4字节,是期望收到对方下一个报文段的第一个数据字节的序号
确认号=N,则表明到序号N-1为止所有数据都正确收到
4)数据偏移:占4位,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远
5)保留:占6位,保留为今后使用
6)紧急URG:当URG=1时,表明紧急指针字段有效,告诉系统此报文中有紧急数据,应尽快传送,而不采用原来的按排队顺序来传送
7)确认ACK:当ACK=1时确认号字段有效,TCP规定,在连接建立后所有数据报文段都把ACK置为1
8)推送PSH:当收到PSH=1的报文时,就尽快交付接收应用进程,而不再等到整个缓存都填满后再向上交付
9)复位RST:当RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后重新建立连接
10)同步SYN:在连接建立时用来同步序号;当SYN=1而ACK=0时,表明这是一个连接请求报文,对*同意建立连接,则应在响应报文中使SYN=1,ACK=1
11)终止FIN:用来释放一个连接,当FIN=1时,表示此报文段的发送方已经发送完毕,并要求释放连接
12)窗口:占2字节,指的是发送本段报文段的一方的接收窗口,窗口值作为接收方让对方设置其发送窗口的依据;窗口字段明确指出了现在允许对方发送的数据量,窗口值经常动态变化
13)校验和:占2字节,检验和字段检验的范围包括首部和数据两部分
14)紧急指针:占2字节,在URG=1时才有意义,指出本报文段中的紧急数据的字节数
15)选项:长度可变,最长40字节
6、TCP可靠传输的实现
1)、以字节为单位的滑动窗口
假定A收到了B发来的确认报文段,其中窗口是20字节,而确认号是31(B期望收到的下一个序号是31,而序号30为止的数据已经收到了)。根据这两个数据,A构造出自己的发送窗口,如下图所示:
发送窗口表示:在没有收到B的确认的情况下,A可以连续把窗口内的数据都发送出去。凡是已经发送过的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用
假定A发送了序号31-41的数据。这时,发送窗口位置并未改变,但发送窗口内靠后面有11个字节表示已发送但未收到确认。而发送窗口内靠前面的9个字节是允许发送但尚未发送的
B收到了序号为32和33的数据,这些数据没有按序到达,因为序号为31的数据没有收到。B只能对按序收到的数据中的最高序号给出确认,因此B发送的确认报文段中的确认号仍然是31
B收到了序号为31的数据,并把序号31-33的数据交付主机,然后B删除这些数据。接着把接收窗口向前移动3个序号(如下图所示),同时给A发送确认,其中窗口值仍为20,但确认号是34。这表明B已经收到了到序号33为止的数据
A在继续发送完序号42-53的数据后,发送窗口内的序号都已用完,但还没有再收到确认。由于A的发送窗口已满,可用窗口已减小到零,因此必须停止发送
发送方的应用进程把字节流写入TCP的发送缓存,接收方的应用进程从TCP的接收缓存中读取字节流
发送缓存用来暂时存放:
- 发送应用程序传送给发送方TCP准备发送的数据
- TCP已发送出但尚未收到确认的数据
接收缓存用来暂时存放:
- 按序到达的、但尚未被接收应用程序读取的数据
- 未按序到达的数据
2)、选择确认SACK
接收方在接收对方发送过来的数据字节流的序号不连续,结构就形成了一些不连续的字节块,如果这些字节的序号都在接受窗口内,接收方就先收下这些数据,但要把这些信息告诉发送方,使发送方不再重复发送这些已收到的数据
左边界为闭,右边界为开;左边界指向字节块第一个字节序号,右边界指向字节块最后一个序号+1
如果要使用SACK,那么在建立TCP连接时,就要在TCP首部的选项中加上允许SACK的选项
7、TCP的流量控制
1)、利用滑动窗口实现流量控制
流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收
滑动窗口的单位是字节。开始时rwnd=400,每个报文段长100字节,接收方的主机B进行了三次流量控制。第一次把窗口减小到。rwnd=300,第二次又减到rwnd=100,最后减到rwnd=0,即不允许发送方再发送数据了
B向A发送了零窗口的报文段后不久,B的接收缓存又有了一些存储空间,于是B向A发送了rwnd=400的报文段。然而这个报文段在传送过程中丢失了。A一直等待收到B发送的非零窗口的通知,而B也一直等待A发送的数据。TCP为每一个连接设有一个持续计时器,只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口探测报文段,而对方就在确认这个探测报文段时给出了现在的窗口值。如果窗口仍然是零,那么收到这个报文段的一方就重新设置持续计时器。如果窗口不是零,A开始发送数据
2)、TCP的传输效率
Nagle算法:若发送应用进程要把发送的数据逐个字节地送到TCP发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文发送出去,同时继续对后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段
糊涂窗口综合征:接收缓存每次只能释放出1字节空间,然后把窗口设为1,向发送方发送确认,发送方又发来1字节数据,接收方发回确认,仍将窗口设为1字节,这样会使网络效率降低
解决方法:让接收方等待一段时间,使得接收缓存有足够空间容纳一个最大的报文段,或等接收缓存中有一半空闲空间。此时再发送确认报文
8、TCP的拥塞控制
1)、拥塞控制的一般原理
出现网络拥塞的条件:
拥塞控制所起的作用:
2)、TCP的拥塞控制方法
1)慢开始和拥塞避免
发送方维持一个叫做拥塞窗口cwnd的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口
只要网络没有出现拥塞,拥塞窗口就可以再增大一些,以便把更多的分组发送出去,这样就可以提高网络的利用率。但只要网络出现拥塞或有可能出现拥塞,就必须把拥塞窗口减小一些,以减少注入到网络中的分组数,以便缓解网络出现的拥塞
在一开始发送方先设置cwnd=1,发送第一个报文段M1,接收方收到后确认M1。发送方收到M1的确认后,把cwnd从1增大到2,于是发送方接着发送M2和M3两个报文段。接收方收到后发回对M2和M3的确认。发送方每收到一个对新报文的确认(重传的不算在内)就使发送方的拥塞窗口加1,因此发送方在收到两个确认后,cwnd就从2增大到4,并可发送M4-M7共4个报文段。因此使用慢开始算法后,每经过一个传输伦次,拥塞窗口cwnd就加倍
慢开始门限:防止拥塞窗口增长过大引起网络拥塞
- 当cwnd<ssthresh时,使用慢开始算法
- 当cwnd>ssthresh时,停止使用慢开始而改用拥塞避免算法
- 当cwnd=ssthresh时,既可用慢开始,也可用拥塞避免
当TCP连接进行初始化时,将拥塞窗口置为1。慢开始门限的初始值设置为16个报文段,即ssthresh=16
拥塞避免是说把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞
当拥塞窗口ssthresh=24时,网络出现超时,发送方判断为网络拥塞。于是调整门限值,同时设置拥塞窗口cwnd=1,进入慢开始阶段
2)快重传
特点:可以让发送方尽早知道发生了个别报文段的丢失
算法思路:要求接收方不等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认
发送方只要一连收到3个重复确认,就立即进行重传(即快重传)
3)快恢复
发送方只是丢失个别报文,不启动慢开始而用快恢复算法,发送方调整门限值ssthresh=cwnd/2,同时设置拥塞窗口cwnd=ssthresh,并开始执行拥塞避免算法(上图点4)
4)拥塞控制流程图
发送方窗口的上限值:发送方的发送窗口一定不能超过对方给出的接收方窗口值rwnd;上限值应取接收方窗口和拥塞窗口这两个变量中较小的一个,即发送方窗口的上限值= min(rwnd,cwnd)
9、TCP的运输连接管理
1)、TCP的连接建立
最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器
1)TCP服务器进程先创建传输控制块TCB,时刻准备接收客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态
2)TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,报文首部中的同部位SYN=1,同时选择一个初始***seq=x ,此时,TCP客户端进程进入了SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号
3)TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文的ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个***seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号
4)TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的***seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号
5)当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了
为什么TCP客户端最后还要发送一次确认呢?
主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误
如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费
如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接收到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接
2)、TCP的连接释放
数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭
1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其***为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的***seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接收。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接收服务器发送的最后的数据)
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的***为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的***是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2*MSL
(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些
为什么客户端最后还要等待2MSL?
MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文
为什么建立连接是三次握手,关闭连接却是四次挥手呢?
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次
3)、TCP的有限状态机
推荐学习资料:
韩老师讲高校《计算机网络原理》:https://www.bilibili.com/video/BV1Tb411x7CE?p=1