以下内容引述至《Linux/Unix系统编程手册》
联网协议通常会被组织成一系列的层,其中每一层都构建与下层之上并提供特性以供上层使用。
ARP:地址解析协议关注的是如何将因特网地址映射到硬件地址
ICMP:用来在网络中传输错误和控制信息(ping和traceroute程序使用),主机和路由器使用因特网组管理协议来支持IP数据报的多播
封装是分层联网协议中的一个重要的原则。封装中的概念是低层会将从高层向低层传递的信息当成不透明的数据来处理。换言之,低层不会尝试对高层发送过来的信息进行解释,而只会将这些信息放到低层所使用的包中并将这个包向下传递到低层之前添加自身这一层的头信息。
数据链路层是由设备驱动和到底层物理媒介的硬件接口构成,关注的是一个网络的物理连接上传输数据。
要传输数据,数据链路层需要将网络层传递过来的数据报封装进被称为帧的一个一个单元。
每个帧除了要传输的数据之外,都会包含一个头,如头中可能包含了目标地址和帧的大小。数据链路层在物理连接上传输帧并处理来自接收者的确认。
这一层可能会进行错误检测、重传以及流量控制。一些数据链路层还可能会将大的网络包分割成多个帧并在接收者段对这些帧进行重组。
数据链路层比较重要的一个特点是最大传输单元(MTU),数据链路层的MTU是该层所能传输的帧大小的上限。
命令 netstat -i 会列出系统中的网络接口,包括其MTU
位于数据链路层之上的网络层,关注的是如何将包从源主机发送到目标主机。这一层执行了很多任务,包括:
IPv4使用32位地址来标志子网和主机,而IPv6使用了128位的地址,为主机提供更大的地址范围。
IP以数据报(包)的形式来传输数据。在两个主机之间发送的每一个数据报都是在网络上独立传输的,它们经过的路径可能会不同。一个IP数据报包含一个头,其大小范围为20字节到60字节。这个头中包含了目标主机的地址,这样就可以在网络上将这个数据报路由到目标地址了。此外,它还包含了源地址,这样接收主机就知道数据报的源头。
IP是一种无连接协议,因为它并没有在相互连接的两个主机之间提供一个虚拟电路。IP也是一种不可靠的协议:它尽最大可能将数据报从发送者传输给接收者,但并不保证包到达的顺序会与他们被传输的顺序一致,也不保证包是否重复,甚至都不保证包是否会达到接收者。
可靠是通过使用一个可靠的传输层协议(如TCP)或应用程序本身来保证的。
IPv4为IP头提供了一个校验和,这样就能够检测出头中的错误,但并没有为包中所传输的数据提供任何错误检测机制。IPv6并没有为IP头提供检验和,它依赖高层协议来完成错误检测和可靠性。
IP数据报的重复是可能发生的,因为一些数据链路层采用了一些技术来确保可靠性以及IP数据报可能会以隧道形式穿越一些采用了重传机制的非TCP/IP网络
IPv4数据报的最大大小为65575字节(40字节存放头信息,65535字节存放数据),并且为更大的数据报(jumbograms)提供了一个选项
当一个IP数据报的大小大于MTU时,IP会将数据报分段(分解)成一个个大小合适在网络上传输的单元。这些分段在达到最终目的地之后会被重组成原始的数据报。
IP分段的发生对于高层协议层是透明的,并且一般来讲也不希望发生这种事情。
问题:由于IP并不进行重传并且只有在所有分段都达到目的地之后不可用。这会导致极高的数据丢失率或降低传输速率。
现在TCP采用了一些算法来确定主机之间的一条路径MTU,并根据该值对传递给IP的数据进行分解,这样IP就不会碰到需要传输大小超过MTU的数据报的情况了。UDP并没有提供这种机制。
一个IP地址包含两个部分:一个是网络ID,它指定了主机所属的网络;另一个是主机ID,它标志了位于该网络中的主机。
一个由32位的网络地址以及一个对应的32位的网络掩码
204.152.189.0/24
这里/24表示分配的地址网络ID由最左边的24位构成,剩下的8位用于指定主机ID。拥有这个地址的组织可以将254(2^8)个唯一的因特网地址分配给其计算机 : 204.152.189.1到 204.152.189.254
有两个地址无法分配,一个是204.152.189.0是标志网络本身,另一个地址的主机ID是204.152.189.255,是子网的广播地址
特殊的IPv4地址:
127.0.0.1 一般被定义为回环地址,通常会被分配给主机名localhost,发送这个地址的数据报实际上不会达到网络,它会自动回环变成发送主机的输入。使用这个地址可以便捷地在同一主机上测试客户端和服务器程序。使用这个地址可以便捷地在同一主机上测试客户端和服务器程序。C语言指定是INADDR_LOOPBACK。
常量INADDR_ANY就是所谓的IPv4通配地址,大多数被定义成了0.0.0.0
一般来讲,IPv4地址是划分子网的。划分子网将一个IPv4地址的主机ID部分分成两个部分:一个子网ID和一个主机ID
子网划分的原理在于一个组织通常不会将其所有主机接到单个网络中。相反,组织可能会开启一组子网(一个“内部互联网络”),每个子网使用网络ID和子网ID组合起来标识。这种组合童话村那个被称为扩展网络ID。
假如分配到的网络ID是204.152.189.0/24,这样可以通过将主机ID的8位中的4位划分成子网ID并将剩余的4位划分成主机ID来对这个地址范围划分子网。这种情况下,子网掩码将由28个前导1后面跟着4个0构成,ID为1的子网将被表示为204.152.189.16/28
IPv6地址由128位构成,其中地址中的前面一些位是一个格式前缀,表示地址类型
IPv6地址通常被书写成一系列用冒号隔开的16位的十六进制数字,如下所示:
F000:0:0:0:0:0:A;1
也通常使用两个冒号(::)来表示这种序列。因此上面的地址可以被重写成
F000::A:1
在IPv6中只能出现一个双冒号标记,出现多次的话会造成混淆。
IPv6也像IPv4地址那样提供了回环地址和通配地址
IPv6支持IPv4映射的IPv6地址格式如下
全0 | FFFF | IPv4地址 |
---|---|---|
80位 | 16位 | 32位 |
举例:与 204.152.189.116 等价的IPv6地址 FFFF:204.152.189.116
在TCP/IP套件中使用广泛的两个数据传输层协议如下:
TCP/IP 协议区分同一主机上不同应用程序,使用的是16位端口号
有些众所周知的端口号已经被永久地分配给特定的应用程序了(或者被称为服务)
一般位于0~1023之间,由中央授权机构互联网号码分配局(IANA)分配
IANA还记录注册端口,范围为1024~41951
在大多数 TCP/IP 协议中,范围在0到1023间的端口号也是特权端口,意味着只有特权进程可以绑定到这些端口上,从而防止了普通用户通过实现恶意程序获取密码。
端口号相同的TCP和UDP端口是不同的实体。
如果一个应用程序没有选择一个特定的端口,那么TCP和UDP会为该socket分配一个唯一的临时端口
IANA将位于49152到65535之间的端口称为动态或私有端口,这表示这些端口可供本地应用程序使用或作为临时端口分配
UDP仅仅在IP上添加了两个特性:端口号和一个进行检测传输数据错误的数据校验和。因此UDP也是不可靠的。
UDP和TCP使用的校验和的长度只有16位并且只是简单的“总结性”校验和,因此无法检出特定的错误,其结果是无法提供较强的错误检测机制。
需要更多确保数据完整性的应用程序可以使用安全Sockets层(SSL),它不仅仅提供了安全的通信,而且还提供更加严格的错误检测过程。
TCP提供了避免IP分段的机制,但UDP并没有提供相应的机制。使用UDP时如果传输的数据报的大小超过了本地数据连接的MTU,那么很容易就会导致IP分段。
基于UDP的应用程序会采用保守的方法来避免IP分段,即确保传输的UP数据报的大小小于IPv4的组装缓冲区大小的最小值576字节。
在576字节中,有8个字节是用于存放UDP头的,另外最少需要使用20字节来存放IP头,剩下的548字节用于存放UDP头的,另外至少需要使用20字节存放IP头,剩下的548字节用于存放UDP数据报本身。
更多的UDP应用程序选择更小的值512自己来存放数据报。
TCP在两个端点之间提供了可靠的、面向连接的、双向字节通信信道。
在开始通信之前,TCP需要在两个端点之间建立一个通信信道。
数据会被分解成段,每一个段都包含一个校验和。每一个段使用单个IP数据报来传输
当一个TCP段无措地达到目的地时,接收TCP会向发生者发送一个确认,通知它数据发送成功。如果一个段在达到时是存在错误的,那么这个段就会被丢弃,确认信息也不会被发送。
为了处理段用不达到或者被丢弃的情况,发送者在发送每一个段时会开启一个定时器。如果在定时器超时之前没有收到确认,那么就会重传这个段。
由于所使用的网络以及当前的流量负载会影响传输一个段和接收器确认所需要时间,因此TCP采用了一个算法来动态地调整重传超时时间(RTO)的大小
接收TCP可能不会立即发送确认,而是会等待几毫秒来观察一下是否可以将确认塞进接收者返回给发送者的响应中。
这项被称为延迟ACK的技术的目的是能少发送一个TCP段,从而降低网络中包的数量以及降低发送和接收主机的负载
在TCP连接上传输的每一个字节都会分配到一个逻辑序号。这个数字指出了该字节在这个连接的数据流中所处的位置。当传输一个TCP分段时会在其中一个字段中包含这个段的第一个字节的序号。作用是:
一个字节流的初始序号(ISN)不是从0开始的,相反,它是通过一个算法来生成的,该算法会递增分配给后续TCP连接的ISN(为防止出现前一个连接中的分段与这个连接中的分段混淆的情况)
流量控制防止一个快速的发送者将一个慢速的接收者压垮。要实现流量控制,接收TCP就必须要为进入的数据维护一个缓冲区。当从发送TCP端收到数据时会将数据累积在这个缓冲区中,当应用程序读取数据时会从缓冲区中删除数据。
TCP流量控制算法采用了所谓的传动窗口算法,它允许包含总共N字节的未确认段同时在发送者和接收者之间传输。如果接收TCP的进入数据缓冲区完全被充满了,那么窗口就会关闭,发送TCP就会停止传输数据。
TCP的拥塞控制算法被设计用来防止快速的发送者压垮整个网络。如果一个发送TCP发送包的速度要快于一个中间路由器转发的速度,那么该路由器就会开始丢弃包。这将会导致较高的丢包率,其结果是如果TCP保持以相同的速度发送这些被丢弃的分段的话,就会极大地降低性能。TCP的拥塞控制算法在下列两个场景中是比较重要的
慢启动算法:发送TCP在一开始的时候以低速传输分段,但同时允许它以指数级的数据提高其速率,只要这些分段都得到接收TCP的确认。慢启动能够防止一个快速的TCP发送者压垮整个网络。但如果不加限制的话,慢启动在传输速率上的指数级增长意味着发送者在短时间内就会压垮整个网络。TCP的拥塞避免算法用来防止这种情况的发生,它为速率的增长安排了一个管理实体。
拥塞避免算法:连接刚建立时,发送TCP会使用一个较小的拥塞窗口,它会限制所能传输的未确认的数据数量。当发送者从对等TCP处接收到确认时,拥塞窗口在一开始时会呈现指数级增长。但一旦拥塞窗口增长到一个被认为是接近网络传输容量的阈值时,其增长速度就会变成线性而不是指数级。在任何时候,发送TCP传输的数据数量还会受到接收TCP的通告窗口和本地的TCP发送缓冲器的大小的限制。
慢启动和拥塞避免算法组合起来,使得发送者可以快速地将传输速度提升至网络的可用容量,并且不会超出该容量。这些算法的作用是允许数据传输快速地到达一个平衡状态,及发送者传输包的速率与它从接收者处确认的速率一致。
公开讨论的每一种因特网协议都是在RFC文档——一个正式的协议规范——中进行定义的。