赞
踩
IP 在 TCP/IP 参考模型中处于第三层,也就是⽹络层。
⽹络层的主要作⽤是:实现主机与主机之间的通信,也叫点对点(end to end)通信。
其实很容易区分,在上⾯我们知道 IP 的作⽤是主机之间通信⽤的,⽽ MAC 的作⽤则是实现「直连」的两
个设备之间通信,⽽ IP 则负责在「没有直连」的两个⽹络之间进⾏通信传输。
既有某个区间的⻋票⼜有整个旅⾏的⾏程表,才能保证到达⽬的地。与此类似,计****算机⽹络中也需要「数据链路层」和「⽹络层」这个分层才能实现向最终⽬标地址的通信。
还有源IP地址和⽬标IP地址在传输过程中是不会变化的(前提:没有使⽤ NAT ⽹络),只有源 MAC 地址和⽬标 MAC ⼀直在变化
因为会根据⼀种可以更换 IP 地址的技术 NAT ,使得可连接计算机数超过 43 亿台。
互联⽹诞⽣之初,IP 地址显得很充裕,于是计算机科学家们设计了分类地址。
IP 地址分类成了 5 种类型,分别是 A 类、B 类、C 类、D 类、E 类。
最⼤主机个数,就是要看主机号的位数,如 C 类地址的主机号占 8 位,那么 C 类地址的最⼤主机个数:
2
8
−
2
=
254
2^{8}-2=254
28−2=254
为什么要减 2 呢?
因为在 IP 地址中,有两个 IP 是特殊的,分别是主机号全为 1 和 全为 0 地址
主机号全为 1 指定某个⽹络下的所有主机,⽤于⼴播
主机号全为 0 指定某个⽹络
⼴播地址⽤于在同⼀个链路中相互连接的主机之间发送数据包。
当主机号全为 1 时,就表示该⽹络的⼴播地址。例如把 172.20.0.0/16 ⽤⼆进制表示如下:
10101100.00010100.00000000.00000000
将这个地址的主机部分全部改为 1,则形成⼴播地址:
10101100.00010100. 11111111.11111111
再将这个地址⽤⼗进制表示,则为 172.20.255.255 。
⽽ D 类和 E 类地址是没有主机号的,所以不可⽤于主机 IP,D 类常被⽤于多播,E 类是预留的分类,暂时
未使⽤
多播⽤于将包发送给特定组内的所有主机。
由于⼴播⽆法穿透路由,若想给其他⽹段发送同样的包,就可以使⽤可以穿透路由的多播。
多播使⽤的 D 类地址,其前四位是 1110 就表示是多播地址,⽽剩下的 28 位是多播的组编号。
从 224.0.0.0 ~ 239.255.255.255 都是多播的可⽤范围,其划分为以下三类:
224.0.0.0 ~ 224.0.0.255 为预留的组播地址,只能在局域⽹中,路由器是不会进⾏转发的。224.0.1.0 ~ 238.255.255.255 为⽤户可⽤的组播地址,可以⽤于 Internet 上。
239.0.0.0 ~ 239.255.255.255 为本地管理组播地址,可供内部⽹在内部使⽤,仅在特定的本地范围内
有效
不管是路由器还是主机解析到⼀个 IP 地址时候,我们判断其 IP 地址的⾸位是否为 0,为 0 则为 A 类地
址,那么就能很快的找出⽹络地址和主机地址。
其余分类判断⽅式参考如下图:
缺点⼀
同⼀⽹络下没有地址层次,⽐如⼀个公司⾥⽤了 B 类地址,但是可能需要根据⽣产环境、测试环境、开发
环境来划分地址层次,⽽这种 IP 分类是没有地址层次划分的功能,所以这就缺少地址的灵活性。
缺点⼆
A、B、C类有个尴尬处境,就是不能很好的与现实⽹络匹配。
C 类地址能包含的最⼤主机数实在太少了,只有254个,估计一个网吧都不够用
⽽ B 类地址能包含的最⼤主机数太多了,6万多个机器放在一个网络下面,一般的企业基本达不到这个规模
正因为 IP 分类存在许多缺点,所以后⾯提出了⽆分类地址的⽅案,即 CIDR 。
这种⽅式不再有分类地址的概念,32 ⽐特的 IP 地址被划分为两部分,前⾯是⽹络号,后⾯是主机号。
表示形式 a.b.c.d/x ,其中 /x 表示前 x 位属于⽹络号, x 的范围是 0 ~ 32 ,这就使得 IP 地址更加具
有灵活性。
⽐如 10.100.122.2/24,这种地址表示形式就是 CIDR,/24 表示前 24 位是⽹络号,剩余的 8 位是主机号。
还有另⼀种划分⽹络号与主机号形式,那就是⼦⽹掩码,掩码的意思就是掩盖掉主机号,剩余的就是⽹络
号。将⼦⽹掩码和 IP 地址按位计算 AND**,就可得到⽹络号。**
因为两台计算机要通讯,⾸先要判断是否处于同⼀个⼴播域内,即⽹络地址是否相同。如果⽹络地址相
同,表明接受⽅在本⽹络上,那么可以把数据包直接发送到⽬标主机。
路由器寻址⼯作中,也就是通过这样的⽅式来找到对应的⽹络号的,进⽽把数据包转发给对应的⽹络内。
在上⾯我们知道可以通过⼦⽹掩码划分出⽹络号和主机号,那实际上⼦⽹掩码还有⼀个作⽤,那就是划分****⼦⽹。
⼦⽹划分实际上是将主机地址分为两个部分:⼦⽹⽹络地址和⼦⽹主机地址。形式如下:
未做⼦⽹划分的 ip 地址:⽹络地址+主机地址
做⼦⽹划分后的 ip 地址:⽹络地址+(⼦⽹⽹络地址+⼦⽹主机地址)
在 A、B、C 分类地址,实际上有分公有 IP 地址和私有 IP 地址。
平时我们办公室、家⾥、学校⽤的 IP 地址,⼀般都是私有 IP 地址。因为这些地址允许组织内部的 IT ⼈员
⾃⼰管理、⾃⼰分配,⽽且可以重复。因此,你学校的某个私有 IP 地址和我学校的可以是⼀样的。
就像每个⼩区都有⾃⼰的楼编号和⻔牌号,你⼩区家可以叫 1 栋 101 号,我⼩区家也可以叫 1 栋 101,没
有任何问题。但⼀旦出了⼩区,就需要带上中⼭路 666 号(公⽹ IP 地址),是国家统⼀分配的,不能两个
⼩区都叫中⼭路 666。
所以,公有 IP 地址是有个组织统⼀分配的,假设你要开⼀个博客⽹站,那么你就需要去申请购买⼀个公有
**IP,**这样全世界的⼈才能访问。并且公有 IP 地址基本上要在整个互联⽹范围内保持唯⼀。
私有 IP 地址通常是内部的 IT ⼈员管理,公有 IP 地址是由 ICANN 组织管理,中⽂叫「互联⽹名称与数
字地址分配机构」。
IANA 是 ICANN 的其中⼀个机构,它负责分配互联⽹ IP 地址,是按州的⽅式层层分配
ARIN 北美地区
LACNIC 拉丁美洲和⼀些加勒⽐群岛
RIPE NCC 欧洲、中东和中亚
AfriNIC ⾮洲地区
APNIC 亚太地区
其中,在中国是由 CNNIC 的机构进⾏管理,它是中国国内唯⼀指定的全局 IP 地址管理的组织。
IP地址的⽹络地址这⼀部分是⽤于进⾏路由控制。
路由控制表中记录着⽹络地址与下⼀步应该发送⾄路由器的地址。在主机和路由器上都会有各⾃的路由器
控制表。
在发送 IP 包时,⾸先要确定 IP 包⾸部中的⽬标地址,再从路由控制表中找到与该地址具有相同⽹络地址
的记录,根据该记录将 IP 包转发给相应的下⼀个路由器。如果路由控制表中存在多条相同⽹络地址的记
录,就选择相同位数最多的⽹络地址,也就是最⻓匹配。
下⾯以下图的⽹络链路作为例⼦说明
路由表找到与⽬标地址 10.1.2.10 相同的⽹络地址,于是包被转发到默认路由(路由器 1 )
了,于是就把 IP 数据包转发到了 10.1.0.2 这台路由器 2
这个接⼝出去,最终经过交换机把 IP 数据包转发到了⽬标主机
环回地址是在同⼀台计算机上的程序之间进⾏⽹络通信时所使⽤的⼀个默认地址。
计算机使⽤⼀个特殊的 IP 地址 127.0.0.1 作为环回地址。与该地址具有相同意义的是⼀个叫做 localhost
的主机名。使⽤这个 IP 或主机名时,数据包不会流向⽹络。
每种数据链路的最⼤传输单元 MTU 都是不相同的,如 FDDI 数据链路 MTU 4352、以太⽹的 MTU 是
1500 字节等。
每种数据链路的 MTU 之所以不同,是因为每个不同类型的数据链路的使⽤⽬的不同。使⽤⽬的不同,可
承载的 MTU 也就不同。其中,我们最常⻅数据链路是以太⽹,它的 MTU 是 1500 字节。
那么当 IP 数据包⼤⼩⼤于 MTU 时, IP 数据包就会被分⽚。
经过分⽚之后的 IP 数据报在被重组的时候,只能由⽬标主机进⾏,路由器是不会进⾏重组的
在分⽚传输中,⼀旦某个分⽚丢失,则会造成整个 IP 数据报作废,所以 TCP 引⼊了 MSS 也就是在
TCP 层进⾏分⽚不由 IP 层分⽚,那么对于 UDP 我们尽量不要发送一个大于MTU的数据报文
我们在上⽹的时候,通常使⽤的⽅式是域名,⽽不是 IP 地址,因为域名⽅便⼈类记忆。
那么实现这⼀技术的就是 DNS 域名解析,DNS 可以将域名⽹址⾃动转换为具体的 IP 地址。
在传输⼀个 IP 数据报的时候,确定了源 IP 地址和⽬标 IP 地址后,就会通过主机「路由表」确定 IP 数据
包下⼀跳。然⽽,⽹络层的下⼀层是数据链路层,所以我们还要知道「下⼀跳」的 MAC 地址。
由于主机的路由表中可以找到下⼀跳的 IP 地址,所以可以通过 ARP 协议,求得下⼀跳的 MAC 地址。
简单地说,ARP 是借助 ARP 请求与 ARP 响应两种类型的包确定 MAC 地址的
主机会通过⼴播发送 ARP 请求,这个包中包含了想要知道的 MAC 地址的主机 IP 地址。
当同个链路中的所有设备收到 ARP 请求时,会去拆开 ARP 请求包⾥的内容,如果 ARP 请求包中的
⽬标 IP 地址与⾃⼰的 IP 地址⼀致,那么这个设备就将⾃⼰的 MAC 地址塞⼊ ARP 响应包返回给主
机
操作系统通常会把第⼀次通过 ARP 获取的 MAC 地址缓存起来,以便下次直接从缓存中找到对应 IP 地址
的 MAC 地址。
不过,MAC 地址的缓存是有⼀定期限的,超过这个期限,缓存的内容将被清除
ARP 协议是已知 IP 地址求 MAC 地址,那 RARP 协议正好相反,它是已知 MAC 地址求 IP 地址。例如将
打印机服务器等⼩型嵌⼊式设备接⼊到⽹络时就经常会⽤得到。
通常这需要架设⼀台 RARP 服务器,在这个服务器上注册设备的 MAC 地址及其 IP 地址。然后再将这个
设备接⼊到⽹络,接着:
该设备会发送⼀条「我的 MAC 地址是XXXX,请告诉我,我的IP地址应该是什么」的请求信息。
RARP 服务器接到这个消息后返回「MAC地址为 XXXX 的设备,IP地址为 XXXX」的信息给这个设
备。
最后,设备就根据从 RARP 服务器所收到的应答信息设置⾃⼰的 IP 地址。
DHCP 在⽣活中我们是很常⻅的了,我们的电脑通常都是通过 DHCP 动态获取 IP 地址,⼤⼤省去了配 IP
信息繁琐的过程。
接下来,我们来看看我们的电脑是如何通过 4 个步骤的过程,获取到 IP 的。
先说明⼀点,DHCP 客户端进程监听的是 68 端⼝号,DHCP 服务端进程监听的是 67 端⼝号。
这 4 个步骤:
不知道 DHCP 服务器的地址,所以使⽤的是 UDP ⼴播通信,其使⽤的⼴播⽬的地址是
255.255.255.255(端⼝ 67) 并且使⽤ 0.0.0.0(端⼝ 68) 作为源 IP 地址。DHCP 客户端将该 IP 数
据报传递给链路层,链路层然后将帧⼴播到所有的⽹络中设备。
该报⽂仍然使⽤ IP ⼴播地址 255.255.255.255,该报⽂信息携带服务器提供可租约的 IP 地址、⼦⽹
掩码、默认⽹关、DNS 服务器以及 IP 地址租⽤期。
DHCP 请求报⽂(****DHCP REQUEST进⾏响应,回显配置的参数。
⼀旦客户端收到 DHCP ACK 后,交互便完成了,并且客户端能够在租⽤期内使⽤ DHCP 服务器分配的 IP
地址。
如果租约的 DHCP IP 地址快期后,客户端会向服务器发送 DHCP 请求报⽂:
服务器如果同意继续租⽤,则⽤ DHCP ACK 报⽂进⾏应答,客户端就会延⻓租期。
服务器如果不同意继续租⽤,则⽤ DHCP NACK 报⽂,客户端就要停⽌使⽤租约的 IP 地址。
可以发现,DHCP 交互中,全程都是使⽤ UDP ⼴播通信
所以,为了解决这⼀问题,就出现了 DHCP 中继代理。有了 DHCP 中继代理以后,对不同⽹段的 IP 地址
分配也可以由⼀个 DHCP 服务器统⼀进⾏管理
DHCP 客户端会向 DHCP 中继代理发送 DHCP 请求包,⽽ DHCP 中继代理在收到这个⼴播包以后,
再以单播的形式发给 DHCP 服务器。服务器端收到该包以后再向 DHCP 中继代理返回应答,并由 DHCP 中继代理将此包⼴播给 DHCP 客
户端 。
因此,DHCP 服务器即使不在同⼀个链路上也可以实现统⼀分配和管理IP地址。
IPv4 的地址是⾮常紧缺的,在前⾯我们也提到可以通过⽆分类地址来减缓 IPv4 地址耗尽的速度,但是互
联⽹的⽤户增速是⾮常惊⼈的,所以 IPv4 地址依然有被耗尽的危险。
于是,提出了⼀种⽹络地址转换 NAT 的⽅法,再次缓解了 IPv4 地址耗尽的问题。
简单的来说 NAT 就是同个公司、家庭、教室内的主机对外部通信时,把私有 IP 地址转换成公有 IP 地址
图中有两个客户端 192.168.1.10 和 192.168.1.11 同时与服务器 183.232.231.172 进⾏通信,并且这两个
客户端的本地端⼝都是 1025。
此时,两个私有 IP 地址都转换 IP 地址为公有地址 120.229.175.121**,但是以不同的端⼝号作为区分。**
于是,⽣成⼀个 NAPT 路由器的转换表,就可以正确地转换地址跟端⼝的组合,令客户端 A、B 能同时与
服务器之间进⾏通信。
这种转换表在 NAT 路由器上⾃动⽣成。例如,在 TCP 的情况下,建⽴ TCP 连接⾸次握⼿时的 SYN 包⼀
经发出,就会⽣成这个表。⽽后⼜随着收到关闭连接时发出 FIN 包的确认应答从表中被删除。
由于 NAT/NAPT 都依赖于⾃⼰的转换表,因此会有以下的问题:
外部⽆法主动与 NAT 内部服务器建⽴连接,因为 NAPT 转换表没有转换记录。
转换表的⽣成与转换操作都会产⽣性能开销。
通信过程中,如果 NAT 路由器重启了,所有的TCP连接都将会被重置
解决的⽅法主要有两种⽅法。
第⼀种就是改⽤ IPv6
IPv6 可⽤范围⾮常⼤,以⾄于每台设备都可以配置⼀个公有 IP 地址,就不搞那么多花⾥胡哨的地址转换
了,但是 IPv6 普及速度还需要⼀些时间。
第⼆种 NAT 穿透技术
NAT 穿越技术拥有这样的功能,它能够让⽹络应⽤程序主动发现⾃⼰位于 NAT 设备之后,并且会主动获得
NAT 设备的公有 IP,并为⾃⼰建⽴端⼝映射条⽬,注意这些都是 NAT设备后的应⽤程序⾃动完成的。
也就是说,在 NAT 穿透技术中,NAT设备后的应⽤程序处于主动地位,它已经明确地知道 NAT 设备要修改
它外发的数据包,于是它主动配合 NAT 设备的操作,主动地建⽴好映射,这样就不像以前由 NAT 设备来
建⽴映射了。
说⼈话,就是客户端主动从 NAT 设备获取公有 IP 地址,然后⾃⼰建⽴端⼝映射条⽬,然后⽤这个条⽬对
外通信,就不需要 NAT 设备来进⾏转换了。
ICMP 全称是 Internet Control Message Protocol,也就是互联⽹控制报⽂协议。
⾥⾯有个关键词 —— 控制,如何控制的呢?
⽹络包在复杂的⽹络传输环境⾥,常常会遇到各种问题。
当遇到问题的时候,总不能死个不明不⽩,没头没脑的作⻛不是计算机⽹络的⻛格。所以需要传出消息,
报告遇到了什么问题,这样才可以调整传输策略,以此来控制整个局⾯
ICMP 主要的功能包括:确认 IP 包是否成功送达⽬标地址、报告发送过程中 IP 包被废弃的原因和改善⽹****络设置等。
在 IP 通信中如果某个 IP 包因为某种原因未能达到⽬标地址,那么这个具体的原因将由 ICMP 负责通****知。
如上图例⼦,主机 A 向主机 B 发送了数据包,由于某种原因,途中的路由器 2 未能发现主机 B 的
存在,这时,路由器 2 就会向主机 A 发送⼀个 ICMP ⽬标不可达数据包,说明发往主机 B 的包未
能成功。
ICMP 的这种通知消息会使⽤ IP 进⾏发送 。
因此,从路由器 2 返回的 ICMP 包会按照往常的路由控制先经过路由器 1 再转发给主机 A 。收到该
ICMP 包的主机 A 则分解 ICMP 的⾸部和数据域以后得知具体发⽣问题的原因
ICMP ⼤致可以分为两⼤类:
⼀类是⽤于诊断的查询消息,也就是「查询报⽂类型」
另⼀类是通知出错原因的错误消息,也就是「差错报⽂类型」
回送消息⽤于进⾏通信的主机或路由器之间,判断所发送的数据包是否已经成功到达对端的⼀种消
息, ping 命令就是利⽤这个消息实现的。
可以向对端主机发送回送请求的消息( ICMP Echo Request Message ,类型 8 ),也可以接收对端主
机发回来的回送应答消息( ICMP Echo Reply Message ,类型 0 )。
相⽐原⽣的 ICMP,这⾥多了两个字段:
标识符:⽤以区分是哪个应⽤程序发 ICMP 包,⽐如⽤进程 PID 作为标识符;
序号:序列号从 0 开始,每发送⼀次新的回送请求就会加 1 , 可以⽤来确认⽹络包是否有丢失。
在选项数据中, ping 还会存放发送请求的时间值,来计算往返时间,说明路程的⻓短
IP 路由器⽆法将 IP 数据包发送给⽬标地址时,会给发送端主机返回⼀个⽬标不可达的 ICMP 消息,并在这
个消息中显示不可达的具体原因,原因记录在 ICMP 包头的代码字段。
由此,根据 ICMP 不可达的具体消息,发送端主机也就可以了解此次发送不可达的具体原因。
举例 6 种常⻅的⽬标不可达类型的代码
同个⼦⽹下的主机 A 和 主机 B,主机 A 执⾏ ping 主机 B 后,我们来看看其间发送了什么?
ping 命令执⾏的时候,源主机⾸先会构建⼀个 ICMP 回送请求消息数据包。
ICMP 数据包内包含多个字段,最重要的是两个?
第⼀个是类型,对于回送请求消息⽽⾔该字段为 8 ;
另外⼀个是序号,主要⽤于区分连续 ping 的时候发出的多个数据包。
每发出⼀个请求数据包,序号会⾃动加 1 。为了能够计算往返时间 RTT ,它会在报⽂的数据部分插⼊发
送时间
然后,由 ICMP 协议将这个数据包连同地址 192.168.1.2 ⼀起交给 IP 层。IP 层将以 192.168.1.2 作为⽬的
地址,本机 IP 地址作为源地址,协议字段设置为 1 表示是 ICMP 协议,再加上⼀些其他控制信息,构
建⼀个 IP 数据包。
接下来,需要加⼊ MAC 头。如果在本地 ARP 映射表中查找出 IP 地址 192.168.1.2 所对应的 MAC 地
址,则可以直接使⽤;如果没有,则需要发送 ARP 协议查询 MAC 地址,获得 MAC 地址后,由数据链
路层构建⼀个数据帧,⽬的地址是 IP 层传过来的 MAC 地址,源地址则是本机的 MAC 地址;还要附加上
⼀些控制信息,依据以太⽹的介质访问规则,将它们传送出去。
主机 B 收到这个数据帧后,先检查它的⽬的 MAC 地址,并和本机的 MAC 地址对⽐,如符合,则接收,
否则就丢弃。
接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的 IP 层。同样,IP 层检查后,将有⽤的信
息提取后交给 ICMP 协议。
主机 B 会构建⼀个 ICMP 回送响应消息数据包,回送响应数据包的类型字段为 0 ,序号为接收到的请
求数据包中的序号,然后再发送出去给主机 A。
在规定的时候间内,源主机如果没有接到 ICMP 的应答包,则说明⽬标主机不可达;如果接收到了 ICMP
回送响应消息,则说明⽬标主机可达。
此时,源主机会检查,⽤当前时刻减去该数据包最初从源主机上发出的时刻,就是 ICMP 数据包的时间延
迟。
针对上⾯发送的事情,总结成了如下图:
当然这只是最简单的,同⼀个局域⽹⾥⾯的情况。如果跨⽹段的话,还会涉及⽹关的转发、路由器的转发
等等。
但是对于 ICMP 的头来讲,是没什么影响的。会影响的是根据⽬标 IP 地址,选择路由的下⼀跳,还有每经
过⼀个路由器到达⼀个新的局域⽹,需要换 MAC 头⾥⾯的 MAC 地址。
说了这么多,可以看出 ping 这个程序是使⽤了 ICMP ⾥⾯的 ECHO REQUEST**(类型为** 8 ) 和 ECHO
REPLY (类型为 0**)**。
有⼀款充分利⽤ ICMP 差错报⽂类型的应⽤叫做 traceroute (在UNIX、MacOS中是这个命令,⽽在
Windows中对等的命令叫做 tracert )。
1. traceroute 作⽤⼀
traceroute 的第⼀个作⽤就是故意设置特殊的 TTL**,来追踪去往⽬的地时沿途经过的路由器。**
traceroute 的参数指向某个⽬的 IP 地址:
traceroute 192.168.1.100
它的原理就是利⽤ IP 包的⽣存期限 从 1 开始按照顺序递增的同时发送 UDP 包,强制接收 ICMP 超时消
息的⼀种⽅法。
⽐如,将 TTL 设置 为 1 ,则遇到第⼀个路由器,就牺牲了,接着返回 ICMP 差错报⽂⽹络包,类型是时
间超时。
接下来将 TTL 设置为 2 ,第⼀个路由器过了,遇到第⼆个路由器也牺牲了,也同时返回了 ICMP 差错报
⽂数据包,如此往复,直到到达⽬的主机。
这样的过程,traceroute 就可以拿到了所有的路由器 IP。
当然有的路由器根本就不会返回这个 ICMP,所以对于有的公⽹地址,是看不到中间经过的路由的。
traceroute 在发送 UDP 包时,会填⼊⼀个不可能的端⼝号值作为 UDP ⽬标端⼝号:33434。然后对于
每个下⼀个探针,它都会增加⼀个,这些端⼝都是通常认为不会被使⽤,不过,没有⼈知道当某些应⽤程
序监听此类端⼝时会发⽣什么。
当⽬的主机,收到 UDP 包后,会返回 ICMP 差错报⽂消息,但这个差错报⽂消息的类型是「端⼝不可
达」。
所以,当差错报⽂类型是端⼝不可达时,说明发送⽅发出的 UDP 包到达了⽬的主机
拔了⽹线, ping 127.0.0.1 是能ping通的。
其实这篇⽂章看到这⾥,标题前半个问题已经被回答了。但是我们可以再想深⼀点。
为什么断⽹了还能 ping 通 127.0.0.1 呢?
⾸先,这是个 IPV4 地址。
IPV4 地址有 32 位,⼀个字节有 8 位,共 4 个字节。
其中127 开头的都属于回环地址,也是 IPV4 的特殊地址,没什么道理,就是⼈为规定的。
⽽ 127.0.0.1 是众多回环地址中的⼀个。之所以不是 127.0.0.2 ,⽽是 127.0.0.1 ,是因为源码⾥就是
这么定义的,也没什么道理。
/* Address to loopback in software to local host. */
#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
IPv4 的地址是 32 位的,2的32次⽅,⼤概是 40+亿 。地球光⼈⼝就76亿了,40亿IP这点塞⽛缝
都不够,实际上IP****也确实⽤完了。
所以就有了 IPV6 , IPv6 的地址是 128 位的,⼤概是2的128次⽅≈10的38****次⽅。据说地球的沙⼦数⼤概是 10的23****次⽅,所以IPV6的IP可以认为⽤不完。
IPV4以8位⼀组,每组之间⽤ . 号隔开。
IPV6就以16位为⼀组,每组之间⽤ : 号隔开。如果全是0,那么可以省略不写。
在IPV4下的回环地址是 127.0.0.1 ,在 IPV6 下,表达为 ::1 。中间把连续的****0给省略了,之所以不是7
个 冒号,⽽是2个冒号: , 是因为⼀个 IPV6 地址中只允许出现⼀次两个连续的冒号。
多说⼀句:在IPV4下⽤的是 ping 127.0.0.1 命令。在IPV6下⽤的是 ping6 ::1 命令。
ping 是应⽤层命令,可以理解为它跟游戏或者聊天软件属于同⼀层。只不过聊天软件可以收发消息,还能
点个赞什么的,有很多复杂的功能。⽽ ping 作为⼀个⼩软件,它的功能⽐较简单,就是尝试发送⼀个⼩⼩
的消息到⽬标机器上,判断⽬的机器是否可达,其实也就是判断⽬标机器⽹络是否能连通。
ping应⽤的底层,⽤的是⽹络层的ICMP****协议。
IP和ICMP和Ping所在分层
虽然ICMP协议和IP协议都属于⽹络层协议,但其实ICMP也是利⽤了IP****协议进⾏消息的传输。
所以,⼤家在这⾥完全可以简单的理解为 ping 某个IP 就是往某个IP地址发个消息
⼀般情况下,我们会使⽤ TCP 进⾏⽹络数据传输,那么我们可以看下它和 ping 的区别。
PS:下图中有⼀处画错了,右边是 tcp 数据,⽽不是 ping 数据,我偷懒就不重画了
ping和其他应⽤层软件都属于应⽤层。
那么我们横向对⽐⼀下,⽐⽅说聊天软件,如果⽤的是TCP的⽅式去发送消息。
为了发送消息,那就得先知道往哪发。linux⾥万物皆⽂件,那你要发消息的⽬的地,也是个⽂件,这⾥就
引出了socket 的概念。
要使⽤ socket , 那么⾸先需要创建它。在 TCP 传输中创建的⽅式是 socket(AF_INET, SOCK_STREAM, 0); ,其中 AF_INET 表示将使⽤ IPV4
⾥ host:port 的⽅式去解析待会你输⼊的⽹络地址。 SOCK_STREAM 是指使⽤⾯向字节流的 TCP 协议,⼯作在传输层。
创建好了 socket 之后,就可以愉快的把要传输的数据写到这个⽂件⾥。调⽤ socket 的 sendto 接⼝的
过程中进程会从⽤户态进⼊到内核态,最后会调⽤到 sock_sendmsg ⽅法。
然后进⼊传输层,带上 TCP 头。⽹络层带上 IP 头,数据链路层带上 MAC 头等⼀系列操作后。进⼊⽹
卡的发送队列 ring buffer ,顺着⽹卡就发出去了。
回到 ping , 整个过程也基本跟 TCP 发数据类似,差异的地⽅主要在于,创建 socket 的时候⽤的是
socket(AF_INET,SOCK_RAW,IPPROTO_ICMP) , SOCK_RAW 是原始套接字 ,⼯作在⽹络层, 所以构
建 ICMP (⽹络层协议)的数据,是再合适不过了。ping 在进⼊内核态后最后也是调⽤的
sock_sendmsg ⽅法,进⼊到⽹络层后加上ICMP和IP****头后,数据链路层加上MAC****头,也是顺着⽹卡发
出。因此 本质上ping 跟 普通应⽤发消息 在程序流程上没太⼤差别。
这也解释了**为什么当你发现怀疑⽹络有问题的时候,别⼈第⼀时间是问你能ping通吗?**因为可以简单理解
为ping就是⾃⼰组了个数据包,让系统按着其他软件发送数据的路径往外发⼀遍,能通的话说明其他软件
发的数据也能通。
前⾯提到,有⽹的情况下,ping 最后是通过⽹卡将数据发送出去的。
那么断⽹的情况下,⽹卡已经不⼯作了,ping 回环地址却⼀切正常,我们可以看下这种情况下的⼯作原
理。
从应⽤层到传输层再到⽹络层。这段路径跟ping外⽹的时候是⼏乎是⼀样的。到了⽹络层,系统会根据⽬
的IP,在路由表中获取对应的路由信息,⽽这其中就包含选择哪个⽹卡把消息发出。
当发现⽬标IP是外⽹****IP时,会从"真⽹卡"发出。
当发现⽬标IP是回环地址时,就会选择本地⽹卡。
本地⽹卡,其实就是个**“假⽹卡”**,它不像"真⽹卡"那样有个 ring buffer 什么的,"假⽹卡"会把数据推到⼀
个叫 input_pkt_queue 的 链表 中。这个链表,其实是所有⽹卡共享的,上⾯挂着发给本机的各种消息。
消息被发送到这个链表后,会再触发⼀个软中断。
专⻔处理软中断的⼯具⼈**“ksoftirqd”** (这是个内核线程),它在收到软中断后就会⽴⻢去链表⾥把消息取
出,然后顺着数据链路层、⽹络层等层层往上传递最后给到应⽤程序。
ping 回环地址和通过TCP等各种协议发送数据到回环地址都是⾛这条路径。整条路径从发到收,都没有经
过"真⽹卡"。之所以127.0.0.1叫本地回环地址,可以理解为,消息发出到这个地址上的话,就不会出⽹
**络,在本机打个转就⼜回来了。**所以断⽹,依然能 ping 通 127.0.0.1 。
以前第⼀次⽤ nginx 的时候,发现⽤这⼏个 IP ,都能正常访问到 nginx 的欢迎⽹⻚。⼀度认为这⼏
个 IP 都是⼀样的。
访问127.0.0.1:80
访问localhost:80
访问0.0.0.0:80
访问本机的IP地址
但本质上还是有些区别的。
⾸先 localhost 就不叫 IP ,它是⼀个域名,就跟 “baidu.com” ,是⼀个形式的东⻄,只不过默认会把它
解析为 127.0.0.1 ,当然这可以在 /etc/hosts ⽂件下进⾏修改。
所以默认情况下,使⽤ localhost 跟使⽤ 127.0.0.1 确实是没区别的。
其次就是 0.0.0.0 ,执⾏ ping 0.0.0.0 ,是会失败的,因为它在 IPV4 中表示的是⽆效的⽬标地址。
$ ping 0.0.0.0
PING 0.0.0.0 (0.0.0.0): 56 data bytes
ping: sendto: No route to host
ping: sendto: No route to host
但它还是很有⽤处的,回想下,我们启动服务器的时候,⼀般会 listen ⼀个 IP 和端⼝,等待客户端的连接。
如果此时 listen 的是本机的 0.0.0.0 , 那么它表示本机上的所有IPV4地址。
/* Address to accept any incoming messages. */
#define INADDR_ANY ((unsigned long int) 0x00000000) /* 0.0.0.0 */
举个例⼦。刚刚提到的 127.0.0.1 和 192.168.31.6 ,都是本机的IPV4地址,如果监听 0.0.0.0 ,那么
⽤上⾯两个地址,都能访问到这个服务器。
当然, 客户端 connect 时,不能使⽤ 0.0.0.0 。必须指明要连接哪个服务器IP。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。