请注意,这与“为什么IP层知道网络堆栈中的更高层?”不是重复的。

基于分组的通信中对协议标识符(例如IP标头的“协议”字段)的需求是明确:这是这种或某种计算密集型推理算法。问题是:为什么它必须作为IP标头的一部分而不是在封装协议的标头中存在? Haskell遇见Go“ ...):一方面,在IP标头中放置“协议”字段会破坏概念上的利益分离,例如OSI模型旨在;另一方面,迫使协议栈中的协议以一致的方式声明其类型要困难得多,并且无论如何最终都会导致类似的情况(例如,如果协议栈中的每个协议都使用其首标头字节说明其类型, ,看起来好像IP使用了它的最后一个标头字节来做同样的事情。)所以我的问题是-将“协议”字段放在IP数据包标头而不是任何地方的背后的原因是什么?其他吗?

编辑:在撰写此问题时,我考虑过是否在“推理”之前添加“原始”一词,即设计IP的团队的推理,但认为这是多余的,因为问题是用过去时表示(“是什么原因……”)。尽管如此,这似乎是必要的,因为没有答复实际上回答了这个问题。注意的一些见解:


@immibis建议以任何其他形式破坏其他协议的模型(例如,加密的通信协议必须具有纯文本标识字段)
@Eddie本质上说,原因是惯例(接受协议链设计,尽管为什么惯例仍然是个谜)
@Ricky强调实用性是最重要的考虑因素
@Claudio建议,如果协议字段是封装标头的一部分,则需要额外的标头识别步骤,该步骤在IP标头解析期间发生的当前模型中

所以我将改写:模型有什么问题,其中每个标头在预定位置(例如,第一个标头字节)标识每个类型,而不是每个标头都标识下一个标头的类型?为什么这样的模型比当前模型更不受欢迎?

编辑#2:似乎答案是给出的几个答案的组合(主要是上面提到的那些以及@Eddie的第二个附录) ):



简单性:在这种特殊情况下,打破层不可知论的原则意味着整个堆栈(或模型)可以更简单:


没有“协议识别”阶段,隐式或显式都没有得到改善
层独立性得到了改善(例如,加密的通信处理程序不必与任何辅助协议共享一个层)

还大大简化了监管,而不必对客户端协议强制执行任何要求。

性能:在数据包本身之前说明封装数据包的协议允许多种类型的快速路由协议(数据包过滤,QOS,直通交换)以集成到网络(互联网)层本身中;这样,它们就可以像访问哈希表一样迅速地做出决定,考虑到该协议旨在在其上运行的有限硬件,这显得尤为重要。

该模型有其缺点,但似乎对于普通情况而言,它比替代方案更适合。

评论

如果协议编号是封装数据的一部分,并且您不知道封装数据的格式(因为您不知道协议),那么您如何知道在哪里可以找到协议编号?

很好地改写您的问题。现在您要问的更有意义。我想我有一个答案,但是我要花一天左右的时间仔细研究一下,以确保它有意义。

“模型出了什么问题,其中每个标头都在预定位置标识了自己的类型,而不是每个标头都标识下一个标头的类型?”因为那样,实际上它实际上只是IPv4标头(或其他低层协议)标头的最后一个字节,而不是名称。这是一个“鸡还是蛋”的问题。如果不知道标题是什么协议,则无法解析标题。

在下面的答案中添加了我的想法。另外,我认为@reirab提出了一个奇妙的观点。

是什么使您说“在IP标头中放置协议字段会破坏概念上的利益分离,例如OSI模型所针对的利益”?较低的协议始终具有有关较高协议的信息:您可以将其视为元数据。正是这一功能允许分层,而不仅仅是一些实际的解决方法:这是一项要求。暗示下层可以识别自己的选择方式,将真正打破利益分离。对于类似的问题,您可以查看文件扩展名vs(Macintosh)类型代码vs Unix“魔术”模式。

#1 楼

请记住,位以一系列的1和0到达NIC。必须存在一些规定来解释应如何解释下一个系列的1和0。

Ethernet2是L2的实际标准,因此假定将前56位解释为Preamble,并且接下来的8位作为前导码,接下来的48位作为目标MAC,接下来的48位作为源MAC,依此类推。

唯一的变化可能是过时的802.3 L2报头,它早于当前的Ethernet2标准,但还包括一个SNAP报头,用于相同的目的。但是,我离题了。

标准的Ethernet2 L2标头有一个Type字段,该字段告诉接收节点如何解释后面的1和0:


否则,接收实体将如何知道L3标头是IP还是IPv6? (或AppleTalk,IPX或IPv8等...)

L3标头(与上述相同)具有“协议”字段,该字段告诉接收节点如何解释下一组IP头后面的1和0中的第一个:


再次,如果没有这个,接收实体将如何知道将那些位解释为ICMP数据包?它也可以是TCP或UDP或GRE,或者是另一个IP标头,也可以是很多其他标头。的位。否则,接收端将不得不使用试探法(或其他类似策略)首先识别标头的类型,然后解释并处理这些位。这将增加每层的大量开销,并在数据包处理中带来明显的延迟。

此时,它很想查看TCP头或UDP头并指出这些头没有Type或Protocol字段...但是回想一下,一旦TCP / UDP解释了这些位,它将有效载荷传递给应用程序。毫无疑问,它可能具有某种标记,至少可以标识L5 +协议的版本。例如,HTTP在HTTP请求中内置了一个版本号:(1.0 vs 1.1)。



编辑以跟原始海报的编辑讲话:


一个模型有什么问题,其中每个标头在预定位置(例如第一个标头字节)标识每个类型,而不是每个标头都标识下一个标头的类型?为什么这样的模型比当前的模型更不受欢迎?


在尝试回答这个问题之前,我认为值得一提的是,可能没有确定的百万美元答案为什么一种方法更好?在这两种情况下,协议标识自身与协议标识其封装的内容,接收实体都将能够正确地解释这些位。

那,我认为协议标识下一个协议有几个原因标头更有意义:

#1

如果标准是用于每个标头的第一个字节来标识自己,那么这将为每一层的每个协议设置标准。这意味着如果只有一个字节专用,那么我们将只能有256个协议。即使您专用了两个字节,也将您的上限设置为65536。无论哪种方式,它都会对可以开发的协议数量进行任意限制。

如果一个协议仅负责解释下一个协议,即使每个协议标识字段专用一个字节,也至少要“缩放”最大256个字节到每个层。

#2

协议对字段进行排序的方式仅允许接收实体选择检查最低限度的最小值以做出决定的选项,只有在前一个报头中存在下一个协议字段时,该协议才存在。

Ethernet2和“剪切”通过“开关”浮现在脑海。如果将前几个字节强制用作协议标识块,这将是不可能的。

#3

最后,我不想相信,但我认为@reirab在原始问题的注释中的答复非常可行:


因为这实际上只是IPv4的最后一个字节(或任何较低级别的协议)除名称外的所有标题。这是一个“鸡还是蛋”的问题。如果不知道标头是什么协议,则无法解析标头。


引用了Reirab的许可

评论


是的,除TCP或UDP外,还有其他现有的第4层协议。 IP并不真正在意有效负载中包含的内容,包括尚未发明的协议。

–罗恩·莫潘♦
16年2月2日,下午5:06

@Eddie那是什么数据包捕获程序?

–利维
16年2月2日在9:34

@Levi:看起来像WireShark。

–垫子
16年2月2日,11:13

@Levi很难低估了解Wireshark对于参与网络的任何人的价值。他们在年度会议SharkFest上放出了很多视频,说明了它的价值并教授了许多高级概念。

–杰夫·梅登(Jeff Meden)
16年2月2日在17:07

此外,关于TCP和UDP没有协议/有效负载类型字段的原因,您是完全正确的。以太网和IP旨在将其有效负载传递到OS网络堆栈中的下一个更高级别,而TCP和UDP旨在将其有效负载直接传递给特定套接字上的应用程序。应用程序已经知道在该套接字上期望使用哪种协议。操作系统需要了解足够的知识,才能知道如何将数据包路由到正确的目标套接字,但是该套接字的所有者应该已经知道下一个更高层协议应该是什么。

– reirab
16年2月3日在5:00



#2 楼

您也可能会问,为什么以太网头具有“以太类型”字段。网络堆栈需要知道下一个更高层中的哪个协议获取当前层的有效负载。

编辑1:

每个数据报都具有该协议的原因下一个上层是创建层独立性。每一层都不在乎有效负载中的内容,也不需要查看有效负载来确定将有效负载传递到何处。将标头中的协议号视为要交付有效负载的地址。就像TCP端口号是TCP地址一样,它们告诉TCP将有效负载传递到哪里。

目标MAC地址告诉网络交换机哪个帧传递接口。以太网类型字段告诉第2层将其有效载荷传递到哪里,IP报头中的协议字段告诉第3层将其有效载荷传递到哪里,TCP和UDP中的端口号告诉第4层将其有效载荷传递到哪里。 br />
想像一个18轮卡车司机,他钩在拖车上以将其运送到某个地方。他无需担心预告片中有什么或将使用什么。他只是看着自己的文书工作,然后将其交付到文书工作中。

您需要记住,每个协议都是独立开发的,不知道将使用哪种新兴的上层协议。长期以来,以太网上使用的主要第3层协议是IPX。如果以太网是专门为IPX创建的,那么今天会无处不在吗?以太网通过具有以太类型字段来构建,以承载任何第3层协议,网络堆栈可使用该字段来决定以太网有效负载的去向。 IP的作用相同,TCP和UDP也是如此。这是一种简单且合乎逻辑的方法,这就是为什么网络堆栈中每个独立开发的层都有一个等效的原因。您和任何其他感兴趣的人,可以自由地为可以轻松插入网络堆栈的任何层开​​发自己的协议,因此。

编辑2:

它允许不同的第3层协议注册到第2层。您可以同时运行IPX(0x8137),IPv4,(0x0800),ARP(0x0806),IPv6(0x86DD)等协议,并且第2层将知道已向其注册了哪些协议并将有效负载传递至相应的层- 3协议,而无需了解任何有关有效负载的信息(或丢弃没有注册协议的任何数据包)。您不需要为每个拥有的第3层协议组合都安装不同的第2层协议,如果第2层协议必须了解有关第3层协议的更多信息,则需要),以便能够读取数据包标头。甚至IPv4和IPv6数据包标头也大不相同。

这里是不同的第3层协议的值的不完整列表,可能已在第2层注册。

第4层协议还注册了各种第3层协议,而应用程序也注册了第4层协议。

您最初的问题是,各层应该彼此独立,这种事情实际上促进了层的独立性,而不是像您建议的那样破坏它。第2层不知道有效负载是IPv4,它仅知道以太类型是0x0800,它应该将有效负载传递给已注册该以太类型的第3层协议。

评论


这个。这是编程优化。您如何在不枚举数据结构的情况下知道哪种数据结构适用。它的逻辑位置在IP标头(“转发声明”)中。请记住,IP是在计算机能力远远不足的时代设计的。

–瑞奇
16年2月2日在1:00

@RickyBeam不,这不是优化。这是类型ID。您不能使其成为更高协议数据的一部分,因为那样您就需要知道用于解码数据的协议-显然,这有点循环:)

–罗安
16年2月2日在9:18

#3 楼

不是您问题的直接答案,而是:


一方面,在IP标头中放置“协议”字段会破坏OSI旨在实现的利益概念分离for。


TCP / IP的开发没有参考OSI模型。尽管它们具有一些共同点,但这是一项单独的开发工作。

评论


谢谢。我最初使用的是“ OSI模型旨在实现的目标”,在这种情况下,它更加准确。我改一下。

– Docom
16年2月2日,11:16

#4 楼

最简单的原因是帮助解析何时接收到数据包。

如果知道遵循哪个协议,则可以制定更严格的约束。 IP数据包中唯一动态的方面是大小(IP选项的存在会以四个字节的倍数增加此大小)。

在解析阶段,您可以检查ip标头的长度,协议。然后,在低级数据包验证中,将通过数据结构(通常是icmp,tcp,udp标头)读取数据包数据,并通过简单数据包进行验证。

#5 楼

只需阅读标题:

当IP数据包包含TCP数据时,协议号字段中的值将为6,因此有效负载将被发送到TCP堆栈,然后TCP将使用端口号将数据发送到正确的应用程序。协议号为17的UDP也是一样。承载一种类型的数据,同时添加此字段允许IP承载按协议号区分的多种类型的数据,对于使用TCP / UDP端口为多个应用程序服务的TCP / UDP和使用以太类型的以太网,以此类推。