《Computer Networks》Fifth Edition中文版笔记

5.6 Internet的网络层

  1. 模块开发。这条原则直接导致了协议栈的思想,每一层的协议完全独立于所有其他的协议。
  2. 寻找好的而不是完美的设计。通常设计者有一个好的设计,但是它不能够处理一些怪异的特殊情况。设计者不应该乱改设计,而是坚持这个好的设计,将围绕着特殊情况而展开的工作负担转移到那些强烈要求的人身上。

5.6.1 IPv4协议

  1. IP数据报头的传输从左到右并从上到下,Version字段的高序字节最先被传送出去(这就是“big-endian”网络字节序。在little-endian字节序机器上,比如Intel x86计算机,在传输和接收时需要进行字节顺序的软件转换)。现在回想起来,little-endian字节序是更好的选择,但在设计IP协议时没有人能预测到今天little-endian流行计算世界。
  2. 由于头的长度不固定,所以头的IHL字段指明了头到底有多长(以32位字长度为单位)。
  3. 最初时,服务类型字段包含6位,其中3位表示优先级,3位表示主机最关心的延迟、吞吐量或可靠性中的哪一个。然而,没人真正知道路由器用这些位做什么,因此这些位空着许多年没人用。在设计区分服务时,IEFT承认自己的失败,并重新启用这个字段。现在,前6位用来标记数据包的服务类别(加速服务和确保服务);后2位用来携带显式拥塞通知信息,比如数据包是否经历了拥塞。
  4. 标识(Identification)字段的用途是让目标主机确定一个新到达的分段属于哪一个数据报。同一个数据报的所有段包含同样的标识值。
  5. 在每一跳上该计数器必须被递减,而且,当数据报在一台路由器上排队时间较长时,该计数器必须多倍递减。
  6. 校验算法的执行过程是这样的:当数据到达时,所有的16位(半字)累加起来,然后再取结果的补码。该算法的目的是到达数据包的头校验和计算结果应该为0。在每一跳必须重新计算头校验和字段,因为至少有个字段总是不断在改变(即生存期字段)。
  7. 选项:严格源路由——给出数据报遵循的完整路径(对于系统管理员,这个选项非常有用,他们可以在路由表被破坏时发送紧急数据包,或者用这个选项来测量时间);松散源路由——给出一些不能错过的路由器;记录路由——要求每个路由器加上自己的IP地址;时间戳——要求每个路由器加上自己的IP地址和时间戳。
  8. 如今,IP选项已失宠。许多路由器忽略它们或者不能有效地处理它们,它们作为一种罕见案例被搁置了起来。也就是说,它们只是得到部分支持,但很少被使用。

5.6.2 IP地址

  1. 重要的是要注意,一个IP地址并不是真正指向一台主机,而是指向一个网络接口,所以如果一台主机在两个网络上,它必须有两个IP地址。与此相反,路由器有多个接口,从而有多个IP地址。
  2. 前缀的主要优势是路由器仅仅根据地址的网络部分即可转发数据包,只要每个网络都有一个唯一的地址块。
  3. 这样可使得路由表远远小于按每个IP地址索引所需要的大小,考虑到Internet的主机数量已接近十亿,这对于每个路由器需要维护的路由表来说实在是太大了。然而,通过分层的方式路由器只需要保持约30万条前缀的路由。
  4. 虽然使用层次路由使得Internet路由规模化,但它有两个缺点。首先,一个主机的IP地址取决于它位于网络上的位置。比如移动IP这样的设计必须支持主机在网络之间移动,但同时保持相同的IP地址。第二个缺点在于层次结构浪费了地址,除非精心管理地址空间。
  5. 这种分割并不要求均匀,但每片必须对齐以便可以把较低的任何位用作地址的主机部分。在这种情况下,块的一半(一个/17)分配给了计算机科学系,四分之一分配给了电机工程学系(一个/18),八分之一(一个/19)分配给了艺术系,剩余的八分之一未分配。
  6. 如果有必要,子网的划分还可以改变,只需要更新校园网内部路由器上的所有子网掩码即可。
  7. 对于通往组织外部某个目的地的路由,这些路由器可以利用简单的默认路由把数据包发送到通往ISP的线路上,ISP把组织与Internet其余部分相连。
  8. ISP和骨干路由器之间的路由没有这样奢侈,这些骨干路由器位于Internet中间。它们必须知道通过哪些方式可到达每个网络,这里没有简单的默认路由可用。
  9. 我们可以运用与子网划分相同的观点:不同地点的路由器可以知道一个给定IP地址的不同大小前缀。然而,不是将一块地址分割成子网,相反,在这里我们把多个小前缀的地址合并成一个大前缀的地址块。这个合并过程称为路由聚合(route aggregation),由此产生的较大前缀地址块有时称为超网(supernet),以便有别于地址块的分割。
  10. 由于4096个地址的块必须位于4096的字节边界上,所以,牛津大学申请的地址不可能从194.24.8.0开始。相反,它们获得了从194.24.16.0至194.24.31.255的地址块,子网掩码为255.255.240.0。
  11. 更为扭曲的是前缀允许重叠。规则是数据包按最具体路由的方向发送,即具有最少IP地址的最长匹配前缀(longest matching prefix)。
  12. 相反,最长匹配前缀路由可以用图中显示的两个前缀来转发。一个总的前缀指示把整个地址块的流量发到伦敦;一个更具体的前缀用来指示该大前缀的一部分流量发往旧金山。
  13. 当一个数据包到达时,路由器扫描路由表以便确定目的地是否在前缀的地址块内。有可能多个具有不同前缀的表项得到匹配,在这种情况下,使用具有最长前缀的表项。
  14. 相反,人们设计了复杂的算法来加快地址匹配过程。商用路由器使用了定制的VLSI,这些算法被嵌入到了硬件中。
  15. 尤其是,真正的罪魁祸首是B类网络。在现实中,一个B类地址对大多数组织而言还是过于庞大。研究表明,超过半数的B类网络少于50台主机。一个C类网络足够应付得过来。但毫无疑问,每个组织都会申请一个B类地址,它们想到总有一天自己的网络规模将超过8位主机地址空间的范围。
  16. 今天,表明一个IP地址是否属于A、B或C类网络的标志位已不再使用,但在文献中队这些类的引用仍然很普遍。
  17. 具有正确的网络号和主机字段全1的地址允许机器向在Internet任何地方的遥远局域网发送广播数据包。然而,许多网络管理员禁用了此功能,主要原因在于这是一个安全隐患。最后127.xx.yy.zz形式的地址保留给回环测试用。发送到该地址的数据包并没有被真正放在线路上,它们如同入境数据包一样在本地处理。这样在发送方不知道网络号的情况下,可以给主机发送数据包,这对测试网络软件很有用。
  18. 这种地址转换使用了IP地址的三个范围,这些地址已经被声明为私有化。任何网络可以在内部随意地使用这些地址。仅有的规则是不允许包含这些地址的数据包出现的Internet上。这3个保留的地址范围是:
    10.0.0.0~10.255.255.255/8 (16777216个主机)
    172.16.0.0~172.31.255.255/12 (1048576个主机)
    192.168.0.0~192.168.255.255/16 (65536个主机)
  19. NAT盒子通常与防火墙组合成一个单一设备,防火墙提供了一种安全机制,它仔细地控制着进出客户网络的流量。另外还有一种可能,将NAT盒子集成到路由器或者ADSL调制解调器中。
  20. 该端口称为源端口,它告诉TCP代码凡是属于该连接的入境数据包都应该发送给该端口。
  21. 任何时候当出境数据包进入NAT盒子,其源地址10.x.y.z被客户的真实IP地址所取代,而且,TCP的source port字段被一个索引值取代,该索引值指向NAT盒子的地址转换表中65536个表项之一。该表项包含了原来的IP地址和原来的源端口。最后,NAT盒子重新计算IP头和TCP头的校验和,并将校验和插入到数据包中。这里之所以要替换source port域,是因为来自机器10.0.0.1和10.0.0.2连接可能碰巧使用了同一个端口,比如都使用了5000,所以仅仅使用source port还不足以唯一性地标识发送进程。
  22. 当一个数据包从ISP到达NAT盒子时,source port从TCP头中提取出,并被用作为索引值查找NAT盒子的映射表。
  23. 实际上,这意味着,家庭网络用户可以通过NAT与一台远程Web服务器建立TCP/IP连接,但远程用户无法与家庭网络内的一台游戏服务器建立连接,这种情况需要特殊的配置技术或者NAT穿越(NAT traversal)技术。
  24. 如果NAT盒子崩溃,并且它的映射表丢失,那么它的所有TCP连接都将被摧毁。没有NAT的情况下,路由器可以崩溃并重启,对TCP连接没有长远影响。发送进程只是在几秒钟内发生超时,然后重传所有未被确认的数据包。使用了NAT之后,Internet如同电路交换网络一样,变得非常脆弱。

5.6.3 IPv6协议

  1. 如果整个地球,包括陆地和水面都被计算机覆盖,那么,IPv6将保证每平方米有7*10^25个地址。化学系的学生将会注意到,这个数值超出了阿伏伽德罗常数。
  2. IHL字段没有了,因为IPv6头有固定的长度。协议(Protocol)字段也被拿掉了,因为下一个头(Next header)字段指明了最后的IP头后面跟的是什么(比如UDP或者TCP段)。
  3. 简要地说,当主机发送了一个非常大的IPv6数据包时,如果路由器不能转发这么大的数据包,它并不对该数据包进行分段,而是向发送主机返回一条报错消息。这条消息告诉主机,所有将来发送给该目标地址的数据包都要分段。让主机从一开始就发送大小合适的数据包,比让沿途路由器动态地对每个数据包进行分段要有效得多。
  4. 最后,校验和(Checksum)字段也被去掉了,因为计算校验和会极大地降低性能。现在使用的大多是可靠网络,而且数据链路层和传输层常有它们自己的校验和,所以在网络层上再使用校验和,相比它所付出的性能代价是不值得的。
  5. 逐跳头(hop-by-hop header)用来存放沿途所有路由器必须要检查的信息。到现在为止,已经定义了一个选项:支持超过64KB的数据报。使用这种扩展头时,固定头中的有效载荷长度(Payload length)字段要设置为0。
  6. 然而,与IPv4不同的是,在IPv6中,只有源主机才可以将一个数据包进行分段。沿途的路由器可能不会进行分段。这一改变是对原始IP的重大哲学突破,但是符合IPv4的现行做法;而且它简化了路由器的工作,使得路由过程更快。
  7. 而且,随着Internet的增长,越来越多的长距离链路将被建立起来,从而使得从一个国家到达另一个国家可能至多不超过六跳。如果从源端和接收方分别到达它们相应的国际网关需要超过125跳,那么它们的国家主干网一定有问题了。
  8. 反对派则认为,真正的安全应用一般只需要端到端的加密,其中源端应用完成加密过程,接收方应用完成解密过程。网络层的实现可能会有错误,用户对此没有任何控制能力却要受到它的约束。

5.6.4 Internet控制协议

  1. 源抑制(SOURCE QUENCH)消息以前被用来抑制那些发送太多数据包的主机。当一台主机接收到这条消息时,它应该将发送速度减慢下来。这种消息现在很少使用了,因为当拥塞发生的时候,再发这些包无疑是火上浇油。现在,Internet的拥塞控制任务主要由传输层完成。
  2. 回显(ECHO)和回显应答(ECHO REPLY)消息可以用来判断一个指定的目标是否可达,以及是否还活着。目标主机接收到回显消息之后,应该立即送回一个回显应答消息。这些消息主要被ping工具用在探测Internet上是否存在某一台特定的主机。
  3. 路由器通告(ROUTER ADVERTISEMENT)和路由器恳求(ROUTER SOLICITATION)消息使得主机拥有寻找附近路由器的能力。主机至少需要学习一个路由器的IP地址才能发送离开本地网络的数据包。
  4. 这时候,主机1上的IP软件构建一个以太网帧,其目标地址为E2,并且把IP数据包(目标地址为192.32.65.5)放到以太网帧的有效载荷字段中,然后将它发送到以太网上。
  5. 首先,一旦一台机器已经运行了ARP,那么,它可以将结果缓存起来,以便稍后它与同一台机器通信时再用。当下次通信时,它就可以在缓存中找到所需的地址映射关系。
  6. 保持缓存信息最新状态并能优化性能的一种更聪明的方式是,让每台机器配置之后广播它的地址映射关系。这次广播通常以ARP的形式发送,即主机发送一个ARP请求查找它自己的IP地址。按理来说,网络上应该不会有任何应答,这个广播数据包的副作用就是其他主机在ARP缓存中加入一个映射表项。这就是所谓的免费ARP(gratuitous ARP)。
  7. 还有一种可能,当主机1不知道主机4在另一个不同网络时,仍然可以从主机1发送一个数据包给主机4.解决办法是让CS网络上的路由器回答针对主机4的ARP请求,并且以E3作为响应。直接由主机4来响应对自己的ARP请求报文是不可能的,因为它根本看不到ARP请求(路由器不会转发以太网级的广播报文)。然后,路由器将收到发给192.32.63.8的帧,并将该帧转发给EE网络。这个解决方案称为ARP代理(proxy ARP)。
  8. 当计算机启动时,它有一个嵌入在NIC中的内置以太网地址或其他链路层地址,但没有IP地址。像ARP一样,该计算机在自己的网络上广播一个报文,请求IP地址。这个请求报文就是DHCP DISCOVER包,这个包必须到达DHCP服务器。如果DHCP服务器没有直接连在本地网络,那么必须将路由器配置成能接收DHCP广播并将该请求报文中继给DHCP服务器,由DHCP服务器来处理DHCP报文。
  9. 当DHCP服务器收到请求,它就为该主机分配一个空闲的IP地址,并通过DHCP OFFER包返回给主机(这个报文或许也要通过路由器中继)。为了在主机没有IP地址的情况下完成此项工作,服务器用主机的以太网地址来标识这台主机(主机的以太网地址由DHCP DISCOVER包携带过来)。
  10. 如果一个主机离开网络,并且没有把分配给它的IP地址返回给DHCP服务器,那么该地址将永久丢失。过一段时间,很多地址都可能因此而丢失。为了防止这种情况发生,可以为每个分配的IP地址指定一段固定时间,这种技术成为租赁(leasing)。在租赁期满前,主机必须请求DHCP续订。
  11. 常见的配置信息例子包括网络掩码、默认网关的IP地址、DNS服务器和时间服务器的IP地址。DHCP已在很大程度上取代了先前使用的协议(称为RARP和BOOTP),因为这些协议的功能比较有限。

5.6.5 标签交换和MPLS

  1. 还有另一种技术正在开始广为应用,特别是被ISP用来在它们的网络之间移动Internet流量。这种技术成为多协议标签交换(MPLS, MultiProtocol Label Switching),它非常接近电路交换。
  2. MPLS在每个数据包前面增加一个标签,路由器根据数据包标签而不是数据包目标地址实施转发。用标签作为一个内部表的索引,快速查找该表找出正确的输出线路,因而这只是一个表查操作。
  3. 由于IP数据包并不是针对虚电路设计的,所以在IP头并没有刻意存放虚电路号的空间。由于这个原因,必须要在IP数据包的头前面加上一个新的MPLS头。如果从一台路由器到另一台路由器之间的线路使用PPP作为成帧协议,那么帧格式中包含了PPP、MPLS、IP和TCP头。
  4. 它不是一个真正的第3层协议,因为它依赖IP或其他网络层地址来建立标签路径;但它也不是一个真正的第2层协议,因为它既可以在多跳之间转发数据包,也不是一条单一链路。
  5. 这个属性还意味着有可能制造出能同时转发IP数据包和非IP数据包的MPLS交换机,具体如何转发取决于线路上出现的是什么。这个特性就是MPLS名字中“多协议”的由来。
  6. 当一个MPLS增强型数据包到达一个标签交换路由器(LSR,Label Switched Router),标签就被用作查找一个表的索引,以便确定要使用的出境路线和新标签。所有的虚电路网络几乎都采用这种标签替换技术。标签只有本地意义,两个不同的路由器可以给两个都到另一台路由器但相互之间毫无关系的数据包分配相同的标签,这两个数据包的进一步传输将使用同一条出境线路。为了在虚电路的另一端能区别出这两个数据包,标签必须在每一端重新进行映射。
  7. 由于大多数主机和路由器都不理解MPLS,因此我们还应该考虑何时以及如何把标签附加到数据包上。这事发生在一个IP数据包到达MPLS网络边缘。标签边缘路由器(LER,Label Edge Router)检查数据包的目标IP地址和其他字段,确定该数据包应当遵循哪条MPLS路径,然后右侧的标签贴在数据包前。
  8. MPLS与传统虚电路的一个区别是聚合水平。在通过MPLS网络时,为每个流设置它自己的一组标签当然是可能的;然而,对于路由器来说,更常见的做法是将终止在某个特定路由器或者LAN的多个流合并成一组,并为这些流使用同一个标签。这些被合起来共享同一个标签的流称为属于同一个转发等价类(FEC,Forwarding Equivalence Class)。
  9. 当已标记的数据包到达这条路径的开始端点处,另一个标签被添加到数据包的前面。这就是所谓的标签栈(stack of label)。最外面的标签指导这些数据包沿着这条公共路径前行。
  10. S标志位告诉删除外层标签的路由器是否还剩下额外的标签。对于最底部的标签,该标志位设为1;而对所有其他标签,该标志位设置为0。
  11. 在传统的虚电路网络,当用户希望建立一个连接时,会向网络发出一个设置包,通过该包来创建路径并生成转发表的表项。
  12. 转发信息由一些协议设置,这些协议一般是路由协议和连接建立协议的组合。这些控制协议与标签转发分离得干干净净,这种分离具有可以使用多个不同控制协议的便利。其中一个变种是这样工作的:当路由器启动时,它会检查看看自己是哪些路由的最终目的地(例如,哪个前缀属于它的接口);然后它为这些路由创建一个或多个FEC,并且为每个FEC分配一个标签,再把新标签发送给其邻居;如此一般地往外传播,直到所有的路由器都获得了相应的路径。

5.6.6 OSPF——内部网关路由协议

  1. 该协议在1990年成为标准,它就是开放最短路径优先(OSPF,Open Shortest Path First)。它借鉴了另一个成为中间系统到中间系统(IS-IS,Intermediate-System to Intermediate-System)的协议,该协议已经成为一个ISO标准。由于它们的共同根源,这两个协议非常的大同小异。它们在域内路由协议中占有绝对的优势,大多数路由器制造商都同时支持这两个协议。OSPF更广泛地应用在公司网络,而IS-IS则更多地应用在ISP网络。
  2. 第六,必须支持层次化系统。到1988年,一些网络已经增长到相当大的规模,以至于任何一台路由器都不可能知道其完整的拓扑结构。OSPF必须设计成不要求路由器知道完整的拓扑结构也能很好地工作。
  3. 这里主机被省略了,因为它们在OSPF中通常不起作用,真正参与路由协议的是路由器和网络(其中可能包含主机)。
  4. OSPF的工作方式本质上是对一张图进行操作:将一组实际网络、路由器和线路抽象到一个有向图中,图中的每条弧有一个权值(距离、延迟等)。广播网络用一个节点表示,加上网络上每台路由器用一个节点表示,从网络节点到路由器节点之间的弧段权值为0。其他网络只有主机,因此只需要一条到达网络的弧,没有返回弧。这种结构使得路由可以到达主机但不能穿过主机。
  5. OSPF可以将这样的AS划分成编号的区域(area),每个区域是一个网络,或者一组互连的网络。区域不能相互重叠,但是也不必面面俱到,也就是说有些路由器可能不属于任何一个区域。全部属于一个区域的路由器称为内部路由器(internal router)。区域是单个网络的一种泛化形式。在区域外部,能见到的是它的目的地而不是拓扑结构。
  6. 每个AS有一个骨干区域(backbone router),称为0号区域。该区域中的路由器称为骨干路由器(backbone router)。所有区域都必须连接到骨干区域,连接方式有可能会通过隧道进行:所以,从AS内的任何一个区域出发,经过骨干区域,总是有可能到达该AS的任何其他区域。
  7. 每个连接到两个或更多区域的路由器成为区域边界路由器(border router)。它必须是骨干区域的一部分。区域边界路由器的工作任务:概括本区域的目的地信息并注入到与自己连接的其他区域。这种概括包含成本信息,但不包括区域内的所有拓扑细节。
  8. 然而,如果只有一个边界路由器通往区域外,甚至路由信息概要都不需要传递。通往该区域外部目的地的路由总是被指令“前往边界路由器”,这类区域称为存根区域(stub area)。
  9. 最后一种路由器是AS边界路由器(AS boundary router)。它把通往其他AS的外部路由注入到本区域。然后外部路由就呈现为可以通过AS边界路由器可达的目的地,该路由当然会有某种成本。
  10. 在正常操作期间,每个区域内的路由器有相同的链路状态数据库,并运行相同的最短路径算法。其主要工作是计算从自身出发到每个其他路由器和整个AS内网络的最短路径。区域边界路由器需要所有与之连接区域的数据库,并且为每个区域分别运行最短路径算法。
  11. 为了避免出现这样的情形,OSPF要求从每个LAN中选举一台路由器作为指定路由器(designated router)。指定路由器与本LAN上的所有其他路由器是邻接的,并且与它们交换信息。实际上,它就是一个代表本LAN的单个节点。邻居但不是邻接的路由器相互之间并不交换信息。有一台备份的指定路由器总是保持最新的状态数据,以便缓解主指定路由器崩溃时的转接和取代主指定路由器的需要。
  12. 通过洪范法,每个路由器把它与其他路由器和网络的链路以及链路成本告诉给它所在区域中的所有其他路由器。这些信息使得每台路由器都可以构建出它所在区域的拓扑图,并且计算最短路径。骨干区域也是这样工作的。而且,为了计算出从每个骨干路由器到每个其他路由器的最佳路由,路由器还要接受来自每个区域边界路由器的信息。最佳最佳路由信息又被传回到区域边界路由器,区域边界路由器再将这些信息在本区域内广播。利用这些信息,内部路由器可以选择通往区域外目的地的最优路由,包括通向骨干区域的最佳出口路由器。

5.6.7 BGP——外部网关路由协议

  1. 然而,它可能不愿意承载那些源自一个外部AS而终止于另一个外部AS的数据包,即使它自己的AS正好位于这两个外部AS之间的最短路径上(“那是他们的问题,不关我们的事”)。
  2. 假设AS2和AS3之间有大量的流量需要交流。由于它们的网络早就连接,因此如果它们愿意,它们可以使用不同的政策——直接给彼此发送免费流量。这将减少必须通过AS1替它们传递的流量,并有望降低它们的账单。这一政策成为对等(peering)传输。
  3. AS3仅仅通告了一条到B的路径给AS4,并没有通告一条到A的路由。因此,流量无法从AS4传到AS3,再传到AS2,即使存在一条物理路径。这种限制正是AS3所希望得到的,它与AS4对等交换流量,但不希望运载来自AS4去往Internet其他地方的流量,因为它得不到对方支付的这笔中转费用。相反,AS4从AS1获得中转服务。
  4. 路由通告消息中携带完整的路径易于让接收路由器发现和打破路由循环。相应的规则是每个路由器在往AS外部发送路由时附加上自己的AS编号(这就是为什么列出的路径是相反顺序的)。
  5. 给出一个AS列表来指定一条路径是非常粗糙的表达方式。一个AS可能是一个小公司,也可能是一个国际骨干网络。没有任何途径告知这些路由的详情,BGP甚至不去尝试了解。因为不同的AS可能使用不同的域内路由协议,因此这些路由协议的成本无法比较;即使它们能相互比较,一个AS或许还不愿意透露其内部的路由度量值。这正是域间路由协议与域内路由协议在方式上的不同所在。
  6. 在ISP内部传播路由通告有一定的规则:位于ISP边界的每个路由器为了一致性,要学习所有其他边界路由器看到的路由。如果ISP的一个边界路由器学习到一个去往IP 128.208.0.0/16的前缀,那么该ISP的所有其他路由器都要学习这个前缀。然后从ISP的任何地方都可到达该前缀,不管数据包从其他AS如何进入ISP。
  7. 例如,路由器R2b知道通过顶部的路由器R2c或者底部的路由器R2d可以到达C。随着路由在ISP内穿越,下一跳得到更新,因此位于ISP远端的路由器知道使用另一侧的哪些路由器离开ISP。这就是为什么最左边的路由看到的下一跳路由器在同一个ISP内,而不是下一个ISP内的路由器。
  8. 第一个策略,优先选择通过对等网络的路由,而不是通过中转提供商的路由。
  9. 另一种不同的策略是将“短路径更好”作为默认规则。这个规则值得商榷。因为一个AS可能是任何规模的网络,所以通过三个小AS的路径实际上可能通过一个大AS的路径短。
  10. 最后一个策略是优先选择具有ISP内最小成本的路由。这么选择的原因在于无论A和B采取的都是离开AS1最小成本路由或者最快路由。因为A和B位于ISP的不同部分,因为对它们每个来说离开AS的最快出口是不同的。同样的事情发生在数据包通过AS2。在最后一站,AS3必须用自己的网络来运载来自B的数据包。

6.4 Internet传输协议:UDP

6.4.1 UDP概述

  1. 实际上,采用UDP而不是原始IP的最主要价值在于增加了源端口和目标端口。如果没有端口字段,传输层将无从知道如何处理每个入境数据包;而有了端口字段之后,它就能把内嵌的段递交给正确的应用程序处理。
  2. 它校验头、数据和一个概念性的IP伪头。在UDP校验和计算中包含伪头将有助于检测出被错误递交的数据包,但是传输层在计算校验和时需要地址的做法违反了协议分层原则。
  3. UDP协议特别有用的一个领域是客户机-服务器应用开发。一般情况下,客户端向服务器发送一个简短的请求报文,并期待来自服务器的简短回复报文。如果请求或回复报文丢失,客户端就会超时,然后再试一次。以这种方式使用UDP的一个应用是域名系统(DNS,Domain Name System)。

6.4.2 远程过程调用

  1. 在最简单的形式中,为了调用一个远程过程,客户程序必须绑定(链接)到一个小的库过程,这个库过程称为客户存根(client stub),它代表了客户地址空间中的服务器过程。类似地,服务器需要绑定到一个称为服务器存根(server stub)的过程。
  2. 第1步是客户调用客户存根。这是一个本地过程调用,其参数按照常规的方式压入到栈中。在第2步,客户存根将参数封装到一个消息中,然后通过系统调用发送该消息。封装参数的过程称为列集(marshalling)。在第4步,操作系统将入境数据包传递给服务器存根。最后,在第5步中,服务器存根利用散集(unmarshaled)得到的参数调用服务器过程。
  3. 对于RPC,传递指针是不可能的,因为客户和服务器位于不同的地址空间中。
  4. 实际上,整个过程相当于用按复制-恢复调用(call-by-copy-restore)代替了按引用调用(call-by-reference)的标准调用序列。不幸的是,这种技巧并不总是能正确地工作,例如,若指针指向一个图形或者其他复杂的数据结构。由于这个原因,对于远程调用的参数必须强加一些限制。

6.4.3 实时传输协议

  1. 这些流被送入到RTP库中,RTP库和多媒体应用一起都位于用户空间。在套接字的操作系统那一端,RTP数据包被封装到新生成的UDP数据包,这些UDP数据包被交给IP,以便发送到链路上,比如以太网。
  2. 如果一个数据包丢失,则接收方能够采取的最佳动作是交给应用程序来处理。如果数据包携带的是视频数据,或许可以跳过该视频帧;如果数据包携带的是音频数据,或许可以利用插值法近似地估计出已丢失的值。重传不是一种切合实际的选择方式,因为重传的数据包可能到达得太晚以至于不再有用。因此,RTP没有确认,也没有请求重传的机制。
  3. 有效载荷类型(payload type)说明使用了哪一种编码算法(比如未压缩的8位音频、MP3等)。由于每个数据包都带有这个字段,所以在传输过程中可以改变编码方法。
  4. RTCP的第一个功能是可以向源端提供有关延迟、抖动、带宽、拥塞和其他网络特性的反馈信息。编码进城充分利用了这些信息,当网络状况比较好的时候,它提高数据速率;而当网络状况不好时候,它减低数据率。
  5. 在现场直播的媒体应用中,比如语音IP电话,延迟的数据包通常会被跳过去。

6.5 Internet传输协议:TCP

6.5.1 TCP概述

  1. 为简化起见,我们有时候仅仅用“TCP”来代表TCP传输实体(一段软件)或者TCP协议(一组规则)。

6.5.2 TCP服务模型

  1. 每个套接字有一个套接字编号(地址),该编号由主机的IP地址以及一个本地主机的16位数值组成的。这个16位数值称为端口(port),端口是TCP的TSAP名字。
  2. 因此,一般的做法是让一个守护进程同时关联到多个端口上,然后等待针对这些端口的第一个入境连接。这个特殊的守护进程在UNIX中称为inetd(Internet daemon)。当出现一个入境连接请求,inetd就派生出一个新的进程,在这个进城中调用适当的守护程序,然后由这个守护程序来处理连接请求。按照这种方式,除了inetd,其他所有守护程序都只在确实有工作需要它们做时才被真正激活。inetd通过一个配置文件知道哪个端口应该使用哪个守护程序。因此,系统管理员可以这样配置系统使得比较忙的端口(比如80端口)使用永久守护程序,而其他端口则让inetd来处理。
  3. TCP不支持组播或广播传输模式。
  4. 为了强制将数据发送出去,TCP有个PUSH标志位概念,由数据包携带的PUSH标志原意是让应用告诉TCP不要延迟传输。然而,应用程序在发送数据时不能从字面上设置PUSH标志。相反,不同的操作系统已经演化了不同的方案来加速传输(例如,在Windows和Linux的TCP_NODELAY)。

6.5.3 TCP协议

  1. TCP的一个关键特征,也是主导整个协议设计的特征是TCP连接上的每个字节都有它自己独有的32位序号。
  2. 当该段到达接收方时,接收端的TCP实体返回一个携带了确认号和剩余窗口大小的段,并且确认号的值等于接收端期望接收的下一个序号。

6.5.4 TCP段的头

  1. 这个连接标识符就被称为5元组,因为它由5个信息组成:协议(TCP)、源IP地址和源端口号、目标IP地址和目标端口号。
  2. 确认号是累计确认(cumulative acknowledgement),因为它用一个数字概括了接收到的所有数据,它不会超过丢失的数据。
  3. 当采用RFC3168说明的显示拥塞通知(ECN,Explicit Congestion Notification)时,CWR和ECE就用作拥塞控制的信号。当TCP接收端收到了来自网络的拥塞指示后,就设置ECE以便给TCP发送端发ECN-Echo信号,告诉发送端放慢发送速率。TCP发送端设置CWR,给TCP接收端发CWR信号,这样接收端就知道发送端已经放慢速率,不必再给发送端发ECN-Echo信号。
  4. 如果使用了紧急指针(urgent pointer),则将URG设置为1。紧急指针指向从当前序号开始找到紧急数据的字节偏移量。
  5. RST被用于突然重置一个已经变得混乱的连接,混乱有可能是由于主机崩溃,或者其他什么原因造成的。该标志位也可以被用来拒收一个无效的段,或者拒绝一个连接请求。一般而言,如果你得到的段被设置了RST位,那说明你遇到问题了。
  6. 本质上,SYN位被用来同时表示CONNECTION REQUEST和CONNECTION ACCEPTED,然后进一步用ACK位来区分这两种可能情况。
  7. TCP中的流量控制是通过一个可变大小的滑动窗口来处理的。窗口大小(window size)字段指定了从被确认的字节算起可以发送多少个字节。
  8. 用途最广的选项允许每台主机指定它愿意接受的最大段长(MSS,Maximum Segment Size)。
  9. 对于具有高带宽、高延迟,或者两者兼备的线路,64KB的窗口对应于16位的字段是个问题。在一条OC-12的线路上(大约600Mbps),只需1毫秒就可输出一个完整的64KB窗口。如果往返传播延迟是50毫秒(越洋光缆的典型值),则发送端将有98%空闲,等待确认的到来。大的窗口允许发送端不停地送出数据。窗口尺度(window scale)选项允许发送端和接收端在连接建立阶段协商窗口尺度因子。双方使用尺度因子将窗口大小字段向左移动至多14位,因此允许窗口最大可达2^30个字节。大多数的TCP实现都支持这个选项。
  10. 时间戳选项还可以被用作32位序号的逻辑扩展。在一条快速连接上,序号空间很快回绕到零,这样导致分不清新数据包和老数据包。防止序号回绕(PAWS,Protection Against Wrapped Sequence numbers)方案根据时间戳丢弃入境段,从而解决这个序号回绕问题。
  11. 最后,选择确认(SACK,Selective ACKnowledgement)选项使得接收端可以告诉发送端已经接收到段的序号范围。

6.5.5 TCP连接建立

  1. 另一端,比如说客户,执行CONNECT原语,同时说明它希望连接的IP地址和端口、它愿意接受的最大TCP段长,以及一些可选的用户数据(比如口令)等参数。CONNECT原语发送一个SYN标志位置为on和ACK标志位置为off的TCP段,然后等待服务器的响应。
  2. 当这个段到达接收方时,那里的TCP实体检查是否有一个进程已经在目标端口字段指定的端口上执行了LISTEN。如果没有,则它发送一个设置了RST的应答报文,拒绝客户的连接请求。
  3. 看6.2.2 连接建立(第395页)和6.2.3 连接释放(第400页)

6.5.6 TCP连接释放

  1. 为了避免两军对垒问题,需要使用计时器。如果在两倍于最大数据包生存期内,针对FIN的响应没有出现,那么FIN的发送端直接释放连接。另一方最终会注意到似乎没有人在监听连接,因而也会超时。

6.5.7 TCP连接管理模型

  1. 当客户机器上的一个应用程序发出CONNECT请求,本地的TCP实体创建一条连接记录,并将它标记为SYN SENT状态,然后发送一个SYN段。请注意,在一台机器上可能同时有许多个连接处于打开(或者正在被打开)状态,它们可能代表了多个应用程序,所以,状态是针对每个连接的,并且每个连接的状态被记录在相应的连接记录中。当SYN+ACK到达的时候,TCP发出三次握手过程的最后一个ACK段,然后切换到ESTABLISHED状态。现在可以发送和接收数据了。
  2. 当一个应用结束时,它执行CLOSE原语,从而使本地的TCP实体发送一个FIN段(1),并等待对应的ACK。当ACK到达(2)时,状态迁移到FIN WAIT 2,而且连接的一个方向被关闭。当另一方也关闭时,会到达一个FIN段(3),然后它被确认(4)。现在,双方都已经关闭了连接,但是,TCP要等待一段长度为最大数据包生存期两倍的时间,才能确保该连接上的所有数据包都已寿终正寝,以防万一发生确认被丢失的情形。当计时器超时后,TCP删除该连接记录。断开是四次,服务器端在第二第三次,第二次是立即发送ACK,表明服务器知道客户想要断开连接了,服务器通知应用进程,当服务器被动关闭时,它第三次发FIN给客户,说它已经被动关闭了。但是要到服务器收到客户的第四次ACK时,服务器才正式释放连接。
  3. 服务器执行LISTEN,并等待入境连接请求。当收到一个SYN时,服务器就确认该段并且进入到SYN RCVD状态。当服务器本身的SYN被确认后,就标志着三次握手过程的结束,服务器进入到ESTABLISHED状态。从现在开始双方可以传输数据了。
  4. 当客户完成了自己的数据传输,它就执行CLOSE,从而导致TCP实体发送一个FIN到服务器。然后,服务器接到信号;当它也执行了CLOSE时,TCP实体给客户发送了一个FIN段。当该段的来自客户的确认返回后,服务器释放该连接,并且删除相应的连接记录。这三节可以去看谢希仁的《计算机网络》第224页

6.5.8 TCP滑动窗口

  1. 当窗口变为0时,发送端不能如通常那样发送段了,但这里有两种意外情形。第一,紧急数据仍可以发送,比如,允许用户杀掉远程机器上运行的某一个进城。第二,发送端可以发送一个1字节的段,以便强制接收端重新宣告下一个期望的字节和窗口大小。这种数据包称为窗口探测(window probe)。TCP标准明确地提供了这个选项,来防止窗口更新数据包丢失后发生死锁。
  2. 针对这样的情况,许多TCP实现采用了一种称为延迟确认(delayed acknowledgement)的优化方法。基本想法是将确认和窗口更新延迟50毫秒,希望能够获得一些数据免费搭载过去。
  3. Nagle的建议非常简单:当数据每次以很少量方式进入到发送端时,发送端只是发送第一次到达的数据字节,然后将其余后面到达的字节缓冲起来,直到发送出去的那个数据包被确认;然后将所有缓冲的字节放在一个TCP段中发送出去,并且继续开始缓冲字节,直到下一个段被确认。
  4. 低能窗口综合症(silly window syndrome):初始时,接收端的TCP缓冲区为满,发送端知道这一点。然后,交互式应用从TCP流中读取一个字符,这个动作使得接收端的TCP欣喜若狂,它立刻发送一个窗口更新段给发送端,告诉它现在可以发送1个字节过来。发送端很感激,立即发送1个字节。现在缓冲区又满了,所以,接收端对这1字节的数据段进行确认,同时设置窗口大小为0。这种行为可能会永久地持续下去。
  5. 特别是,只有当接收端能够处理它在建立连接时宣告的最大数据段,或者它的缓冲区一半为空(相当于两者之中取较小的值),它才发送窗口更新值。

6.5.9 TCP计时器管理

  1. 由于在数据链路层中确认极少被延迟(因为不存在拥塞),所以,如果在预期的时间内确认没有到来,则往往意味着帧或者确认已经被丢失了。
  2. 在最初的实现中,TCP使用2*RTT,但经验表明常数值太不灵活,当发生变化时它不能很好地做出反应。尤其是,随机流量的排队模型(即泊松分布)预测的结果是当负载接近容量时,延迟不仅变大,而且变化也大。这可能导致重传计时器超时而重新传输一个数据包的副本,尽管原先的数据包仍然在网络中传输着。
  3. 超时重传值RTO为:
    RTO=SRTT+4×RTTVAR
    平滑的往返时间SRTT:
    SRTT=α×SRTT+(1α)×R (典型情况下, α=7/8 。如果在计时器超时前确认返回,则TCP测量这次确认所花的时间,比如说R)
    往返时间变化RTTVAR:
    RTTVAR=β×RTTVAR+(1β)×|SRTTR|
  4. 重传计时器的最小值为1秒,无论估算值是多少。这是为了防止根据测量获得的欺骗性重传值而选择的保守值。
  5. 在采集往返时间的样值R过程中有可能引发的一个问题是,当一个段超时并重新发送以后该怎么办?不更新任何重传段的估计值。此外,每次连续重传的超时时间间隔加倍,直到段能一次通过为止。
  6. 当持续计时器超时后,发送端给接收端发送一个探寻消息。接收端对探寻消息的响应式是将窗口大小告诉发送端。如果它仍让为0,则重置持续计时器,并开始下一轮循环。如果它非0,则现在可以发送数据了。
  7. 每个TCP连接使用的最后一个计时器被应用于连接终止阶段,即在关闭过程中,当连接处于TIMED WAIT状态时所使用的计时器。它的超时值为两倍于最大数据包生存期,主要用来确保当连接被关闭后,该连接上创建的所有数据包都已完全消失。

6.5.10 TCP拥塞控制

  1. 当路由器上的队列增长到很大时,网络层检测到拥塞,并试图通过丢弃数据包来管理拥塞。传输层收到从网络层反馈来的拥塞信息,并减慢它发送到网络的流量速率。
  2. TCP维持一个拥塞窗口(congestion window),窗口大小是任何时候发送端可以往网络发送的字节数。相应的速率则是窗口大小除以连接的往返时间。TCP根据AIMD(加法递增乘法递减)规则来调整该窗口的大小。
  3. 还有一个流量控制窗口,该窗口指出了接收端可以缓冲的字节数。要并发跟踪这两个窗口,可能发送的字节数是两个窗口中较小的那个。
  4. 开始,他观察到丢包可以作为一个合适的拥塞信号。这个信号来得有点晚(因为网络早已拥挤不堪),但它相当值得信赖。
  5. 然而,用丢包作为拥塞信号依赖于传输错误相对比较少见的场合。对于诸如802.11的无线链路,传输错误比较常见,这也就是为什么它们在链路层有自己的重传机制。
  6. 关键的观察是这样的:确认返回到发送端的速率恰好是数据包通过路径上最慢链路时的速率。这正是发送端应该使用的精确发送速率。这个时序就是确认时钟(ack clock)。这是TCP的基本组成部分。通过使用一个确认时钟,TCP平滑输出流量和避免不必要的路由器队列。
  7. 第二个考虑是如果网络拥塞窗口从一个很小的规模开始,那么在快速网络上应用AIMD规则将需要很长的时间才能达到一个良好的操作点。针对这两种情况,Jacobson选择的解决方案是一个线性增长和乘法增长相混合的方法。
  8. 这种算法成为慢速启动(slow start),但它根本不慢——它呈指数增长——相比以前的算法,即一次发送整个流量控制窗口大小的数据,它应该算启动得不快。
  9. 当发送端得到一个确认,它就把拥塞窗口大小增加1,并立即将两个数据包发送到网络中(其中一个包是新增加的一个;另一个包是替代那个已被确认并离开网络的数据包。任何时候未确认的数据包的数量就是拥塞窗口的大小*这对理解fast recovery非常有用*)。
  10. 经过3个RTT,网络中有四个数据包。这四个数据包经过完整的RTT后到达接收端。也就是说,四个包的拥塞窗口大小就是该连接的正确大小。
  11. 为了保持对慢速启动的控制,发送端为每个连接维持一个称为慢启动阈值(slow start threshold)的阈值。最初,这个值被设置得任意高,可以达到流量控制窗口的大小,因此它不会限制连接速度。
  12. 每当检测到丢包,比如超时了,慢启动阈值就被设置为当前拥塞窗口的一半,整个过程再重新启动。
  13. 一旦慢速启动超过了阈值,TCP就从慢速启动切换到线性增加(即加法递增)。在这种模式下,每个往返时间拥塞窗口只增加一段。像慢速启动一样,这通常也是为每一个被确认的段而不是为每一个RTT实施窗口的增加
  14. 到目前为止这个方案中的缺陷是等待超时。超时时间相对较长,因为它们必须是保守的。当一个包被丢失后,接收端不能越过它确认,因此确认号将保持不变,发送端因为拥塞窗口为满将无法发送任何新包到网络。这种情况可以持续一段比较长的时期,直到计时器被触发和重传丢失的包。在这个阶段,TCP再次慢速启动。
  15. 发送端有一个快速方法来识别它的包已经被丢失。当丢失数据包的后续数据包到达接收端时,它们触发给发送端返回确认。这些确认段携带者相同的确认号,称为重复确认(duplicate acknowledge)。发送端每次收到重复确认时,很可能另一个包已经到达接收端,而丢失的那个包仍然没有出现。
  16. 因为包可以选择网络中不同的路径,所以它们可能不按发送顺序到达接收端。这样就会触发重复确认,即使没有数据包被丢失。然而,这种情况在Internet上并不多见。当存在跨越多条路径的包时,收到的数据包通常需要重新排序的不会太多。因此,TCP有点随意地假设三个重复确认意味着已经丢失一个包。
  17. 重传后,慢启动阈值被设置为当前拥塞窗口的一半,就像发生了超时一样。
  18. 每次到达一个新的确认就增加窗口的大小,而不是连续增加,因而导致窗口的大小表现出离散的阶梯模式。
  19. 在快速重传时,连接还工作在一个太大的拥塞窗口,但它仍然同样以确认时钟的速率在运行。每次到达另一个重复确认时,可能另一个数据包已经离开网络。使用重复确认来计算网络中的数据包,有可能让一些包离开网络,并继续为每一个额外的重复确认发送一个新的包。
  20. 快速恢复(fast recovery)就是实现这种行为的启发式机制。这是一个临时模式,其目的是保持拥塞窗口上运行确认时钟,该拥塞窗口有一个新阈值或者快速重传时把拥塞窗口值减半。要做到这一点,对重复确认要计数(包括触发快速重传机制的那三个重复确认),直到网络内的数据包数量下降到新阈值。这大概需要半个往返时间。从此时往后,每接收到一个重复确认就发送一个新的数据包。快速重传之后的一个往返时间后,丢失的包将被确认。在这个时间点,重复确认流将停止,快速恢复模式就此退出。拥塞窗口将被设置到新的慢启动阈值,并开始按线性增长。
  21. 接收端在正常的方式下使用TCP的确认号字段,作为已收到的最高顺序字节的累计确认。当它接收到乱序的数据包3时(因为数据包2丢失了),它发送一个确认段,其中包括针对包1的(重复)累计确认和包3的SACK选项。
  22. 支持ECN的路由器在接近拥塞时就会在携带ECN标志的数据包上设置拥塞信号,而不是在拥塞发生后丢弃这些数据包。

7.3 万维网

7.3.1 体系结构概述

  1. 让一个页面指向另一个页面的想法现在称为超文本(hypertext),这种想法在1945年由一个卓有远见的MIT电子工程系教授Vannevar Bush发明(Bush, 1945),也就是说早在Internet被发明出来之前就已经有了Web。
  2. 如果每次显示的是相同的一个文档,则称该网页为静态页面(static page)。相反,如果每次显示的是程序按需产生的内容,或者页面本身包含了一个程序,则称该网页为动态页面(dynamic page)。
  3. URL包括3个部分:协议(也称为方案(scheme))、页面所在机器的DNS名字,以及唯一指向特定页面的路径(通常是读取的一个文件或者运行在机器上的一个程序)。一般情况下,路径是一个模仿文件目录结构的层次名字。然而,如何解释路径是服务器的事,而且路径可能反映了实际的目录结构,也可能不反映实际的目录结构。
  4. 使用file协议或者更简单地只要给出一个文件名就有可能通过Web页面来访问本地文件。这种方法并不需要一个服务器。当然,它仅适用于本地文件,而不能用于远程文件。
  5. mailto协议并没有真正抓取网页,但反正是有用的。它允许用户从Web浏览器发送电子邮件。大多数浏览器针对一个mailto链接会以启动用户的邮件代理作为回应,返回一个已填写好地址字段的邮件。
  6. 抛开所有这些漂亮的属性,越来越多的Web使用已经暴露出URL方案中的固有弱点。一个URL指向一个特定的主机,但有时引用一个页面无须告诉它在哪里也是很有用的。例如,对于被大量引用的页面,需要有多个相距甚远的副本,以便减少网络流量。但用户没有办法说:“我希望得到页面xyz,但我不关心在哪里得到它。”
  7. 为了解决这类问题,URL已经被推广到统一资源标识符(URI,Uniform Resource Identifiers)。某些URI告诉浏览器如何定位资源,这些就是URL;其他URI告诉了资源名字,但没有说明到哪里可以找得到它,这些URI就称为统一资源名(URN,Uniform Resource Names)。
  8. 标准的方式是操作系统将文件的扩展与MIME类型关联起来。在典型的配置中,当浏览器打开foo.pdf时,它就会用application/pdf插件,而当打开bar.doc文件时则通过application/msword辅助应用程序调用Word。
  9. 为了解决一次只能服务一个请求的问题,一种策略是将服务器设计成多线程模式(multithread)。在其中一种设计方案中,服务器由一个前端模块(front-end module)和k个处理模块(processing module)组成。
  10. 当一个请求到达时,前端模块接受它,并为其创建一条描述该请求的简短记录,然后将该记录递交给其中一个处理模块。
  11. 乍一看,读者可能会立即想到服务器可以通过观察用户的IP地址来跟踪他们。然而,这个想法并不奏效。首先,许多用户通过共享的计算机工作,特别是在家里;而且IP地址仅仅标识了计算机而不标识用户。其次,更糟糕的是,许多公司使用NAT,因而所有用户发出的出境数据包具有相同的IP地址。
  12. 这个问题的解决方案是采用了一项称为小甜饼(Cookie,它是一小段文本信息,伴随着用户请求页面在Web服务器和浏览器之间传递)的备受批评的技术。
  13. Cookie是一个相当小的命名的串(最多4KB),服务器将它与浏览器关联。这种关联与用户关联不一样,但它非常接近而且比IP地址更有用。
  14. Cookie只是字符串,而不是可执行程序。原则上,一个Cookie可能包含病毒,但由于Cookie只被当作数据处理,因而不存在病毒得以实际运行从而造成损害的正式途径。
  15. 为了从客户的硬盘上删除一个Cookie,服务器只需将它再发送一次,但是将该Cookie的过期时间指定为一个已经过去的时间即可。
  16. 在浏览器向某个Web站点发出一个页面请求之前,浏览器检查它的Cookie目录,确定这个请求前往的目标域是否在当前客户端放置了Cookie。如果存在相应的Cookie,则该域放置的所有Cookie都被包含到请求消息中。
  17. 当她发现一件便宜货并单击它时,服务器将该货物放入她的购物车(由服务器维护),同时创建一个包含商品数量和产品代码的Cookie,并把它发送到客户。当客户继续在商店里闲逛时,每当客户点击一个新页面,该Cookie随着该新页面的请求被返回到服务器端。随着顾客购买的物品累计得越来越多,服务器将它们统统加入到Cookie中。最后,当客户单击“前往结账”(PROCEED TO CHECKOUT)时,这个Cookie现在包含了她想购买商品的完整列表,它和当前的请求一起被发送给服务器。
  18. 一家广告代理商,比如说Sneaky广告,它联系了一些主要的Web站点,在这些站点的页面上放置一些广告来宣传它企业客户的产品,为此它当然向这些站点的所有者支付一定的费用。广告公司并不是向这些站点提供一个放在每个页面上的GIF或JPEG文件,而是提供一个URL,这个URL被加入到每个页面中。广告公司给出的每个URL包含一个路径上的唯一数字,例如http://www.sneaky.com/382674902342.gif。当用户第一次访问一个包含该广告的页面P时,浏览器获取HTML文件。然后浏览器检查该HTML文件,并看到了指向www.sneaky.com上图像文件的链接,因此它向www.sneaky.com发送一个对该图像的请求。一个包含广告的GIF文件,连同一个包含了唯一用户ID的Cookie,一起被返回客户。Sneaky公司记录下这样的事实:此ID的用户曾经访问过页面P。要做到这点很容易,因为被请求的路径(382674902342.gif)只在页面P上被引用过。
  19. 在整个商业中最阴险的环节在于许多用户完全不知道自己的信息被他人收集,甚至可能认为自己是安全的,因为他们没有点击任何广告。出于这个原因,跨站点跟踪用户的Cookie被许多人认为是间谍软件(spyware)。
  20. 大多数浏览器允许用户阻止第三方Cookie。第三方Cookie是从一个不同于主页网站的其他网站获得的Cookie,例如,sneaky.com Cookie就是在与一个完全不同网站的P页面交互时所用的。

7.3.2 静态Web页面

  1. “标记”这个术语来自过去,那时编辑在要印刷的文档上实际标记出有关信息,告诉印刷工(那时还是人工印刷)应该使用什么字体等。
  2. HTML文档的实际布局结构无关紧要。HTML解析器将忽略额外的空格和回车,因为它们必须重新对文本进行格式化,以便使得这些文本适合当前的显示区域。因此,可以任意添加空格使得HTML文档更具可读性,而大部分空格并不是所需要的。
  3. 由于<、>和&有特殊的含义,所以它们只能用转义序列来表示,分别是<、>和&。
  4. 标签分别用来表示进入粗体和斜体模式。
    标签强制中断,并画一条横跨屏幕的水平线。
  5. 标签开始一段。

  6. 在HTML 4.0中,增加了更多的新功能。这些功能包括残障用户的访问功能、对象嵌入(由标签生成,因此其他对象也可以被嵌入到页面中)、支持脚本语言(允许显示动态的内容)以及更多的辅助功能。
  7. HTML 5.0包含了许多功能来处理富媒体,即现在经常在网络上使用的丰富媒体。页面可以包括视频和音频,并且浏览器可以正常播放而无须用户安装插件。画画作为矢量图形可以内置在浏览器中,而不必使用位图图像格式(如JPEG和GIF)。还有更多支持在浏览器中运行脚本,诸如计算和存储访问的后台线程。所有这些功能有助于支持Web页面比文档看起来更像一个具有用户接口的传统应用。这是Web发展的方向。
  8. 表单仍然是静态内容。
  9. 在这些字段之间没有使用

    标签,因此,如果放得下,浏览器会在一行(而不是作为分开的一段段)显示这些字段。

  10. 当用户点击submit按钮时,浏览器将收集到的信息打包成一个很长的行,并将其发送回服务器;该服务器由作为
    标签一部分的URL提供。发送时要用到一个简单的编码。“&”用来分隔字段,“+”用来表示空格。
  11. textarea框也与文本框相同,但是它可以包含多个行。
  12. HTML的最初目标是指定文档的结构,而不是文档的外观。例如:
<h1> Deborah's Photos h1>

一种更好的替代方案是使用样式表(style sheet)。文本编辑器中的样式表允许作者将文本与逻辑风格关联,而不是与物理风格相关,例如,“初始段”而不是“斜体文本”。一个CSS例子:

body {background-color:linen; color:navy; font-family:Arial;}
h1 {font-size:200%;}
h2 {font-size:150%;}

样式表可以被放置在HTML文件中(例如,使用