计算机网络自顶向下方法:第三章 运输层

先根据书中的复习题巩固一遍, 最后回答常见问题TCP三次握手和四次挥手, 若有错误, 欢迎指出~html

点击下面跳过复习题

TCP3次握手: 为何须要初始序号? 为何须要3次握手, 而不是两次握手
TCP4次挥手java

 

第二章: 运输层

3.1~3.3节

R1. 假定网络层提供了下列服务.

  • 在源主机中的网络层接收最大长度1200字节和来自运输层的目的主机地址的报文段. 网络层则保证将该报文段交付给位于目的主机的运输层. 假定在目的主机上可以运行许多网络应用进程.

a. 设计可能最简单的运输层协议, 该协议将使应用程序数据到达位于目的主机的所但愿的进程. 假设在目的主机中的操做系统已经为每一个运行的应用进程分配了一个4字节的端口号.web

b. 修改这个协议, 使它向目的进程提供一个的"返回地址".小程序

c. 在你的协议中, 该运输层在计算机网络的核心中"必须作任何事"吗?浏览器

 
答:缓存

  • a. 我设计的最简单运输层协议将包括两部分: 目的端口号和报文. 由于该协议只要使应用程序数据到达位于目的主机所须要的进程就能够了, 它将会在下发到源主机的网络层时加上目的主机的IP地址, 保证了主机之间的逻辑通讯. 到达目的主机的网络层后会把该运输层报文段提取上交到运输层, 运输层根据目的端口好在本机的网络进程中找到有相同的端口号的目的进程, 并交付应用数据.
  • b. 为了提供让目的进程返回的地址, 在须要加上一个源端口号字段. 这样目的进程就能经过把源端口号设置为目的端口号, 进而向源进程传输数据. (再加上一些其余字段就是个UDP协议了)
  • c. 它并不须要作"任何事", 目前它只提供交付数据的功能, 不具有诸如拥塞控制, 确保数据完整性等功能.

 

R2. 考虑有一个星球,

  • 每一个人都属于某个六口之家, 每一个家庭都住在本身的房子里, 每一个房子都有一个惟一的地址, 而且某给定家庭中的每一个人有一个独特的名字. 假定该星球有一个从源家庭到目的家庭交付信件的邮政服务. 该邮件服务要求: 1. 在一个信封中有一封信; 2. 在信封上清楚地写上目的家庭的地址(而且没有别的东西). 假设每一个家庭有一名家庭成员表明为家庭中的其余成员收集和分发信件. 这些信件没有必要提供任何有关信的接收者的提示.

a. 使用对上面复习题R1的解决方案做为启发, 描述家庭成员表明可以使用的协议, 以从发送家庭成员向接收家庭成员交付信件.服务器

b. 在你的协议中, 该邮政服务必须打开信封并检查信件内容才能提供它的服务吗?网络

 
答:tcp

  • a. 这个问题考察的是运输层协议与上层应用层和下层网络层之间的关系. 下面描述一次收发邮件的过程.
场景 映射
每一个家庭住本身的房子, 房子有惟一地址 每一台主机都有本身的IP地址
家庭中每一个人都有本身独特的名字 主机中运行的每一个进程都有本身惟一的端口号
家庭A一名成员表明家庭A收集全家庭的信件 某个运输层协议, 经过套接字从应用进程获取应用报文
家庭A表明将收集的全部邮件交给邮政服务 运输层协议将运输层报文段交付给网络层 (多路复用)
信封上除了目的家庭地址没有别的东西, 邮政服务把邮件传输到目的家庭B 网络层会将报文段与目的地址IP封装成数据报, 进行主机之间的网络传输
家庭B的表明从邮政服务得到邮件 目的主机的运输层从网络层中接收数据, 抽取出报文段
家庭B的表明把邮件分发给本身家里的成员 目的主机的运输层协议把数据经过套接字上交给应用进程 (多路分解)
  • b. 邮政服务不须要打开信封并检查信件内容, 由于它只负责把邮件从一个家庭住址传送到另外一个家庭. 它并不关心信件的内容. 比如网络层所提供的服务, 它会将传输层报文段封装起来, 报文段的具体内容与它无关.

 

R3. 考虑在主机A和主机B之间有一条TCP链接.

  • 假设从主机A传送到主机B的TCP报文段具备源端口号x和目的端口号y. 对于从主机B传送到主机A的报文段, 源端口号和目的端口号分别是多少?
  • 答: 源端口号将设置为y, 目的端口号设置为x.

 

R4. 描述应用程序开发者为何可能选择在UDP上运行程序而不是在TCP上运行的缘由.

  • 这个问题问的是在什么状况下, UDP的优势明显盖过TCP的缺点.
  • UDP协议是一种极为简化的运输层协议, 它不提供没必要要的服务, 大概就是在IP协议上加上源和目的地的端口后等信息, 因此它能够随时地, 以任何速率向其余端系统发送数据.
  • TCP协议有许多优良特性, 它确保数据完整性, 提供拥塞控制, 但这些特性会增长端到端通讯的时延.
  • 若是一个应用程序须要提供实时服务, 并且可以容忍必定的分组丢失, 那么UDP协议是更好的选择.

 

R5. 在今天的因特网中, 为何语音和图像流量经常是通过TCP而不是经UDP发送.

  • (提示: 咱们寻找的答案与TCP的拥塞控制机制没有关系)
  • 答: 为了确保数据的完整性, 分组丢失可能会对语音和图像质量产生影响.

 

R6. 当某应用程序运行在UDP上时, 该应用程序可能获得可靠的数据传输吗? 若是能, 如何实现?

  • 能够的.
  • 须要经过应用层协议实现. 好比谷歌的Chrome浏览器中所使用的QUIC协议在UDP之上的应用层协议中实现了可靠性.

 

R7. 假定在主机C上的一个进程有一个具备端口号6789的UDP套接字.

  • 假定主机A和主机B都用目的端口6789向主机C发送一个UDP报文段. 这两台主机的这些报文段在主机C都被描述为相同的套接字吗? 若是是这样的话, 在主机C的该进程将怎样知道源于两台不一样主机的这两个报文段?

 

  • 答: 这两台主机的这些报文段在主机C会被描述为相同的套接字. 由于在传输UDP包的时候, 网络层会附带上源和目的的IP地址的, 主机C的程序能够经过不一样的源IP地址判别.
  • 毕竟主机A和B在选端口的时候不知道彼此具体会选什么, 确定会有选用同样端口号的状况, 主机IP能把它们区分开.

 

R8. 假定在主机C端口80上运行一个Web服务器.

  • 假定这个Web服务器使用持续链接, 而且正在接收来自两台不一样主机A和B的请求. 被发送的全部请求都经过位于主机C的相同套接字吗? 若是它们经过不一样的套接字传递, 这两个套接字都具备端口80吗? 讨论和解释之.

 

  • 答: 这里有个巧妙的关系为题目带来歧义.
  • A和B的请求会经过80端口找到服务器进程, 就这里而言它们经过为与C的相同套接字, 这个套接字具备端口80.
  • 当它们与服务器进程创建链接的时候, 服务器进程会单独为它们分配套接字, 经过专门的套接字响应客户端的请求. 这两个套接字就不具备80端口了.

 

R9. 在咱们的rdt协议中, 为何须要引入序号?

  • 若是不引入序号会有什么问题? 描述: 一个初始的rdt停等协议是这样的: 发送方发送一个分组, 发送方进入等待状态, 不能从上层接收分组, 接收方接收到分组后若是分组正常则回复ACK, 不然回复NAK, 发送方接收到ACK则回到初始状态等待上层调用, 若是收到NAK则重传该分组继续等待.
  • 问题来了: 若是接收方的ACK, NAK分组在传输过程当中受损, 发送方该如何处理? 最简单实用的方法就是重传了, 也就是当发送方不肯定接收方是否收到分组就把分组从新发送一遍.
  • 可是重发分组会带来新的问题, 接收方在接收到重发的分组时, 它并不知道这是一个新的分组仍是一个重传的分组(对上一个分组已经确认过了).
  • 因而便引入序号, 这里的序号用一个比特位表示0和1就能解决. 加入当前发送方发送带有0序号的分组, 那么接收方会进行响应. 发送方若是接收到损坏的确认分组, 那么它重传一次带有0序号的分组. 不然传送带1序号的下一个分组. 接收方根据分组的序号进行判断, 若是当前分组的序号和上一个接受到的分组的序号相同, 说明这是一次重传, 若是不相同说明是一个新的分组.
  • 以上基于一个简单的停等协议进行描述.

 

R9. 在咱们的rdt协议中, 为何须要引入定时器?

  • 在上面一题中了解引入序号是为了解决分组在传播过程当中因分组受损, 发送方重传分组而带来的冗余分组问题. 可是在因特网中, 分组除了会受损, 还可能丢失. 这里探讨该经过一个怎样的机制解决分组丢失问题.
  • 若是发送方发送的分组或者接收方响应的确认在传输过程当中丢失, 发送方将收不到确认. 解决这问题的办法还是重传分组, 可是应该在何时进行重传是值得商榷的. 网络中的延时具备很是大的不肯定性, 若是等待足够大的时延才重传分组显然会下降效率. 应该定一个固定的时间, 只要过了这个时间就认为分组丢失(尽管可能没有丢失).
  • 这里便引入了定时器, 在每传输一个分组时开启一个定时器, 并且让发送方响应定时器计时后产生的中断, 还有要关闭计时器的机制.

当集齐检验和, 序号, 定时器, 确定和否认确认分组这些技术后, 一个基本的可靠数据传输协议已经构建好了.动画

 

R10. 假定发送方和接收方之间的往返时延是固定的而且为发送方所知. 假设分组可以丢失的话, 在协议rdt3.0中, 一个定时器还是必需的吗? 试解释之.

  • 若是发送方知道了双方固定的往返时延, 那么就能够不须要定时器了. 由于定时器的存在就是为了估计一个双方的往返时延值, 超过了就进行重传. 如今知道具体且固定的往返时延, 那么就能够准确地得出接受到确认分组的时间, 若是超过了该时间尚未接收到确认就进行重传.

 

R12. 在配套网站上使用Go-Back-N(回退N步)Java小程序.

a. 让源发送5个分组, 在这5个分组的任何一个到达目的地以前暂停该动画. 而后毁掉第一个分组并继续该动画. 试描述发生的状况.

b. 重复该实验, 只是如今让第一个分组到达目的地并毁掉第一个确认. 再次描述发生的状况.

c. 最后尝试发送6个分组. 发生了什么状况?

 

R13. 重复复习题R12, 可是如今使用Selective Repeat(选择重传)Java小程序. 选择重传和回退N步有很么不一样?

 

  • 上面的题目因为没法访问到该小程序暂时跳过, 可是下面的补充会覆盖掉上面两个问题的知识点.

补充:

  • 跳过补充说明

    回退N步

  • 在R11事后已经基本创建起了一个可靠数据传输协议. 可是它传输分组的形式至关于串行传输, 对链路的利用率极低. 可不能够在等待收到确认分组时继续发送分组?
  • 答案是能够的. 可是会引入新的问题, 这样像流水线同样地发送分组, 如何处理丢失, 损坏及延时过大的分组?
  • 解决流水线的差错恢复有两种基本方法是: 回退N步和选择重传.
  • 回退N步从字面上是很好理解的, 先发送一个分组a, 在启动计时器后陆续发送b, c, d ... n, 若是a分组在传输过程当中出现了问题, 那么就从a开始从新传输n个分组.

  • 口头描述一下回退N步的流程, 下面的FSM图描述的更清晰. 首先会发送base序号的分组, 并启动计时器, 而后继续按序发送窗口内的分组, 若是到达了窗口的边界base + N - 1处的分组就停下来, 也就是说发送方须要维护发送窗口的上下边界. 而接收方接收到base分组后会根据base分组的序列号响应回去, 所以接收方只须要维护一个记录分组n被接收到的变量.
  • 当base分组的计时器计时完尚未收到确认, 认为出现分组丢失, 这时无论窗口有边界扩到哪里, 都从base开始重传分组. 因此若是接收方接在收到base分组以前收到后面的分组(失序), 能够直接把失序的分组丢弃掉, 不须要缓存, 由于发送方一定会重传一次.
  • 从这也能得出发送方与接收方都是采用累计确认的方式处理分组.

 

选择重传

  • 在引入选择重传以前, 咱们先看看回退N步协议会带来什么问题. 显然回退N步是一个在流水线式分组传输下一个可靠的协议, 可是若是窗口比较大, 当base分组丢失后, 后面全部的分组都要进行重传, 这会不会比较浪费呢? 考虑每一个分组都丢失一下, 那么重传的次数将达到二次方的数量级.
  • 可不能够哪一个分组丢失了就重传哪一个分组, 而不是重传所有呢? 能够的, 这就引入了选择重传协议. 在理解了回退N步后选择重传应该不是个大问题.

 

  • 对于发送方, 在send_base分组被确认后它窗口才会往左移动, 移动的长度取决于send_base分组旁边有多少个连着的已经确认的分组(选择重传, 容许失序的分组被确认后缓存起来, 等待被确认).
  • 对于接收方, 当接收到rcv_base分组后才会移动窗口, 移动的长度也取决于旁边有多少个连着的失序(已缓存)但未被确认的分组.
  • 从这能看出, 发送方与接收方的窗口并非同步移动的. 这里会引入一个大问题. 见下图:

 

  • 上图描述的问题是如今分组的序列号的取值范围是0~3, 也就是大小为4(以前讲过0~1的), 窗口大小为3.
  • 假设发送方发送了分组0, 1, 2, 发送方所有接收到, 发送方的窗口移动3格, 等待3, 4, 5分组.
  • 不巧的是0, 1, 2三个分组的ACK分组都丢失了, 发送方将重传0, 1, 2三个分组.
  • 这时问题就来了, 假设0, 1, 2分组对应的序列分别为0, 1, 2. 可是4, 5分组对应的序列号也为0, 1. 为了确保发送方的窗口可以滑动, 接收方会缓存rcv_base - N的分组(已经确认), 以便再次收到这个范围上的冗余分组时可以发送一个对应的ACK.
  • 这时发送方发送的分组0带有序号0, 而接收方的既期待分组4(序号为0), 又缓存有分组0(序号为0), 接收方将不知道收到的是分组0仍是分组4.
  • 显然, 若是窗口的长度比序号空间小1时, 可能出现接收方没法肯定接受到的分组是一次重传仍是一个新的分组. - 书上给出的窗口取值范围为: 窗口长度必须小于或等于序号空间大小的一半.

 

继续是复习题

3.5节

R14. 是非判断题

a. 主机A通过一条TCP链接向主机B发送一个大文件. 假设主机B没有数据发往主机A. 由于主机B不能随数据捎带确认, 因此主机B将不向主机A发送确认.
答: 错误. 主机B将不向主机A发送确认这句话违背了一个可靠数据传输协议的基本原则. 首先要明确为了确保可靠的数据传输, 接收方向发送方发送肯定报文是协议的一部分. 再分析推导出这一错误结论的缘由: 主机B不能随数据捎带确认. 书本上提出捎带的概念时, 给的是一个具体场景, 发送方要发送一个字符, 接收方要返回该字符进行回显, 因此顺便把确认信息放入到发给发送方的数据的报文段中. 要区分清楚确认和捎带确认之间的关系.

b. 在整个链接的过程当中, rwnd的长度决不会变化.
答: 错误. rwnd = RcvBuffer - [LastByteRcvd - LastByteRead]. rwnd表示的是接收窗口的大小, 这取决于接收方应用程序从缓存中读取数据的速率和发送方发送的速率, 是会变化的.

c. 假设主机A经过一条TCP链接向主机B发送一个大文件. 主机A发送但未被确认的字节数不会超过接收缓存的大小.
答: 正确. 讲的就是TCP的流量控制.

d. 假设主机A经过一条TCP链接向主机B发送一个大文件. 若是对于这条链接的一个报文段的序号为m, 则对于后继报文段的序号将必然是m + 1.
答: 错误. 序号是根据TCP数据的字节流决定的, 而不是创建在报文序列之上. 后继报文段的序号应该是m + n, 而n是最大报文段长度.

e. TCP报文段在它的首部中有一个rwnd字段.
答: 错误. TCP报文段有接收窗口字段, rwnd存放在接收窗口字段中.

f. 假定在一条TCP链接中最后的SampleRTT等于1秒, 那么对于该链接的TimeoutInterval的当前值一定大于等于1秒.
答: 正确. TimeoutInterval = EstimatedRTT + 4 * DevRTT.

g. 假设主机A经过一条TCP链接向主机B发送一个序号为38的4个字节的报文段. 在这个相同的报文段中, 确认号一定是42.
答: 错误. 概念性错误, 确认号是期待接收方发送的序号.

 

R15. 假设主机A经过一条TCP链接向主机B发送两个紧挨着的TCP报文段. 第一个报文段的序号为90, 第二个报文段序号为110.

a. 第一个报文段中有多少数据?
答: 110 - 90 = 20个字节.

b. 假设第一个报文段丢失而第二个报文段到达主机B. 那么在主机B发往主机A的确认报文中, 确认号应该是多少?
答: 90. 在创建链接的时候主机B就知道要先接收90.

 

R16. 考虑在3.5节中讨论的Talnet的例子.

  • 在用户键入字符C数秒以后, 用户又键入字符R. 那么在用户键入字符R以后, 总共发送了多少个报文段, 这些报文段中的序号和确认字段应该填入什么?
  • 答: 因为用户在键入C数秒后键入R, TCP没有断开链接. 因此键入R后有用户到服务器和服务器到用户两个报文段. 用户到服务器: 序号44, 确认80, 服务器到用户: 序号80, 确认45

 

3.7节

R17. 假设两条TCP链接存在于一个宽带为Rbps的瓶颈链路上.

  • 它们都要发送一个很大的文件(以相同方向通过瓶颈链路), 而且二者是同时开始发送文件. 那么TCP将为每条链接分配什么样的传输速率?
  • 答: 这里涉及到2条TCP链接的公平性问题, 很难保证两条TCP链接分配均等的传输速率. 可是2条TCP链接的速率之和是会在R/2~R之间浮动的. 至于哪条快一点, 哪条慢一点是不肯定的.

 

R18. 是非判断题. 考虑TCP的拥塞控制. 当发送方定时器超时时, 其ssthresh的值将被设置为原来值的一半.

  • 错误. 当发送方定时器超时时, TCP发送方将cwnd设置为1并从新开始慢启动过程. 它还将第二个状态变量的值ssthresh设置为cwnd/2, 即当检测到拥塞时将ssthresh置为拥塞窗口值的一半.

 

R19. 在3.7节的"TCP分岔"讨论中, 对于TCP分岔的响应时间, 断言大约是4 * RTT(FE) + RTT(BE) + 处理时间. 评价该断言.

  • 我认为该断言是合理的. 它给出的是一条包含重要时延参数的公式. 在实际状况中, 某些参数可能能够省略, 可是在省略以前仍是要通过考虑的.

 

插入对TCP协议的总结

  • 3.4节讲的是如何从零建立起一个可靠高效的数据传输协议, 而3.5节基于3.4节的基础具体讲述TCP的实现, 这里有必要对TCP协议进行一个简单的总结.

 

TCP三次握手

在讲述三次握手以前先看看TCP报文段结构

 

  • 对于三次握手问题, 咱们暂时不考虑报文段中的其余字段, 只看报文段中序号和确认号字段. 对这两个字段有印象后, 下面开始描述一次完整的TCP三次握手过程.
  • 故事开始...
  1. 第一步: 客户端TCP向服务器端的TCP发送一个特殊的TCP报文段, 该报文段不包含应用层数据. 报文段首部中的标志位SYN置1, 简称为SYN报文段. 同时客户端随机选取一个初始序列号client_isn, 放置于SYN报文段的序号字段中, 最后把该报文段经下层封装发送给服务器. SYN的意思是: xxx服务器, 我想向你发起TCP链接, 个人初始序号为client_isn.
  2. 第二步: 服务器收到SYN报文段后, 响应一个SYNACK报文段. SYNACK报文段的SYN标志位置1, 确认号字段设置为client_isn + 1, 序号字段由服务器选择本身的初始序号server_isn. SYNACK报文段的意思是: 我收到了你的SYN报文段, 序号为client_isn, 我赞成该链接, 我本身的序号为server_isn.
  3. 第三步: 客户端接收到SYNACK后要告知服务器本身收到了. 因而发送最后一个报文段, SYN标志位置0, 把确认字段设置为server_isn + 1, 并设置本身的序号. 这个报文意思是: 好的, 我知道你赞成了, 咱们开始传输数据吧.

 

在解释序号和确认号以前先解释一下为何是三次握手而不是两次握手.
  • 其实若是上面的过程理解了, 就能回答这个问题了, 不过这里有个漫画帮助理解.
  • 先演示的是三次握手.

 

  • 接着演示两次握手.
明白了为何是三次握手而不是四次挥手后, 再来看TCP报文段中的序号和确认号.
  • 序号:
  • 序号是创建在传送的字节流之上, 而不是创建在传送的报文段的序列之上的. 意思是说若是把传输的数据看做是一个字节文本, 序号则是对文本的首字节进行编号.
  • 我知道仍是很抽象, 看具体例子. 如今要经过TCP发送一个500000字节的大文件, 最大报文长度为1000(一个报文段最多只能装1000个字节). 那么此次TCP传输就要分为500个报文段. 第一个报文段序号为0, 由于在500000字节中首字节的序号为0; 第二个报文段的序号为1000, 由于第一个报文段装了1000个字节, 第二个报文段从第1000个字节开始装起; 同理, 第三个报文段的序号为2000...
  • 为何要使用序号?
  • 发送序号是为了告诉接收方, 下一次我将从哪一个地方开始传数据给你. 接收方同时也会期待下次从下一个字节序列的位置开始接收发送方的数据. 接收方会把这个位置写到确认号中, 好比上面的例子, 接收方在接收到0序列分组后, 会在确认字段填入1000, 下一次期待接收1000位置的字节.
  • 由上可见: 主机A填充进报文段的确认号是主机A指望从主机B收到的下一字节的序号.

 

TCP四次挥手

  • 四次挥手指的是TCP的两端断开链接时的四次报文段传输.

 

  1. 首先客户端TCP向服务器发送一个特殊的TCP报文段, 其中FIN标志位被置1.
  2. 服务器收到该报文段后就向发送方发送一个确认报文段.
  3. 而后服务器发送本身的终止报文段, 一样是把FIN位置1.
  4. 最后客户端对服务器的终止报文段发送确认响应.
  • 两次挥手行不行? 就是客户端提出关闭, 服务器响应后TCP就结束.
  • 答: 不行, 由于客户单方面提出关闭的话, 服务器仍是能够向客户端发送数据, 必须双方都提出关闭并获得确认后TCP链接才算关闭.
相关文章
相关标签/搜索