网络层协议 IP
Posted 原来45
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络层协议 IP相关的知识,希望对你有一定的参考价值。
目录
C语言总结 在这 常见八大排序 在这
作者和朋友建立的社区: 非科班转码社区-CSDN社区云 💖 💛 💙
期待hxd的支持哈 🎉 🎉 🎉
最后是打鸡血环节: 想多了都是问题,做多了都是答案 🚀 🚀 🚀
最近作者和好友建立了一个公众号
公众号介绍:
专注于自学编程领域。由USTC、WHU、SDU等高校学生、ACM竞赛选手、CSDN万粉博主、双非上岸BAT学长原创。分享业内资讯、硬核原创资源、职业规划等,和大家一起努力、成长。( 二维码在文章底部哈! )
IP协议
基本概念
主机 : 配有 IP 地址 , 但是不进行路由控制的设备 ; 路由器 : 即配有 IP 地址 , 又能进行路由控制 ; 节点 : 主机和路由器的统称; 应用层处理的问题:读取完整数据报&&协议处理问题 传输层处理的问题:可靠性(TCP) 网络层处理的问题:让主机具有一种能力,将数据从A发到B 网络层解决的问题就是那个定义,数据是传输层交给网络层去传的,传输层只是保证了数据传输的可靠性。(如果网络层没有把数据传送过去,那么传输层协议会给网络层提供策略,使之100%传输过去,即可靠传输。)(传输层我们流动的数据叫TCP数据段,网络层我们叫IP报文)协议头格式(重要)
PS:注意TCP协议里面是有端口号,IP协议报头里面是放的IP。
- 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4。
- 4位头部长度(header length): IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大的数字是15, 因此IP头部最大长度是60字节。
- 8位服务类型(Type Of Service): 3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0). 4位TOS分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本. 这四者相互冲突, 只能选择一个. 对于ssh/telnet这样的应用程序, 最小延时比较重要; 对于ftp这样的程序, 最大吞吐量比较重要。
- 16位总长度(total length): IP数据报整体占多少个字节。
- 16位标识(id): 唯一的标识主机发送的报文. 如果IP报文在数据链路层被分片了, 那么每一个片里面的这个id都是相同的。
学习IP还有一个重要的点就是分片问题:
就是数据链路层规定的发送数据有上线(减少局部碰撞),那么网络层发送IP报文太大的时候,这个分片工作要发送方的网络层来做,数据收到了网络报文,这个数据的组装也就是对方的网络层进行组装。因为要解耦:
那么现在就是,以前网络层一下发一个报文,现在因为链路层有规定,可能会发现切片变成多个报文(传输层并不关心你的分片,他只负责传),那么将来网络层收到了若干的报文要组合,就可能出现组装不起来的问题(哪怕一片IP报文丢了,那么整个IP报文就认为他是整体丢包了),那么该报文就不会交给传输层,在传输层看来就是数据丢包了。所以网络层分片不是主流,我们尽量让他不分片(后面谈)。
- 3位标志字段: 第一位保留(保留的意思是现在不用, 但是还没想好说不定以后要用到). 第二位置为1表示禁止分片, 这时候如果报文长度超过MTU, IP模块就会丢弃报文. 第三位表示"更多分片", 如果分片了的话,最后一个分片置为0, 其他是1. 类似于一个结束标记。
- 13位分片偏移(framegament offffset): 是分片相对于原始IP报文开始处的偏移. 其实就是在表示当前分片在原报文中处在哪个位置. 实际偏移的字节数是这个值 * 8 得到的. 因此, 除了最后一个报文之外, 其他报文的长度必须是8的整数倍(否则报文就不连续了)。
分片了如何组装:
这就是我们刚刚的 16位标识,三位标识,13位偏移 该做的了。
接收端每收到报文就要检查报头中的3位标准查看第三位(“更多分片”)是否被置1,那么就代表这个报文是被分片过的,再去提取他的序号,再去搜集序号是一样的其他报文放到一起。(就是收到的位1,就代表后面还有分片,如果为0就没有了(如果开始就收到了0(如果分片了的话),那么此报文的13位片偏移一定不为0!)
第二位禁止分片:如果我们IP报文交给数据链路层的数据的时候,如果我们设置了禁止分片意味着我们不想要网络层做分片,那么该报文就会被对应的主机直接丢弃(也就是说我们关闭了他的分片功能)。
如何正确组装?(13位片偏移)
如果你是个独立的报文,那么你的3位标志和13位片偏移也是0,16位标识就是你的标识(和之前的序号一样),但是如果你分片了,那么他也是独立的IP他就是需要设置他的片偏移的,那么组装就非常简单,把片偏移排序就可以了组合起来了(假设一个报文(3000字节)分为3篇(每篇1000),那么他们的序号就可能是0,1000,2000这样,注意这只是去理解才这样说)。那么判断是否片偏移就是:
(更多分片==1)||(更多分片==0 && 偏移!=0)
那怎么保证收集完了呢?(收完并不一定收全)
就是收到大部分三位标志是1,只有一个是0且13位片偏移为特定值。
那怎么保证你收全了呢?
可以经过片偏移排序来确定,如果起始片偏移不为0,或者中间数据不连续(自己的偏移量加上自身的长度就是下一个报文的起始偏移量,如果对不上那么就肯定不全)反之,然后组合起来,就可以得到我们分前的报文了。
通过这三步,就可以对我们的报文进行组装了。1. 先识别该报文是否被分片的
2. 将序号相同的报文先收集在一起
3. 正确组装
- 8位生存时间(Time To Live, TTL): 数据报到达目的地的最大报文跳数. 一般是64. 每次经过一个路由, TTL-= 1, 一直减到0还没到达, 那么就丢弃了. 这个字段主要是用来防止出现路由循环。
就是因为特殊原因如目标主机不可达又或者网络原因导致IP报文在网络中长时间游离,而不消失,这样的数据没有意义了,防止累计,所以有这个8位生存时间给他生命周期。(比如设置为5,那么每经过一个路由器,那么他的生命周期就--,为0报文就直接丢弃)
- 8位协议: 表示上层协议的类型。
- 16位头部校验和: 使用CRC进行校验, 来鉴别头部是否损坏。
在分片后我们也要保证他的组合是符合预期的,所以在最后合并之后(网络层),可以去通过16位首部校验和检查报头有没有问题。因为分片组装最重要的不是数据出问题,而是标志位出问题,所以他对首部做校验。(16位头部校验和: 使用CRC进行校验, 来鉴别头部是否损坏)(至于为什么不校验数据呢?因为TCP/UDP他也有他自己的16位校验和,如果是数据本身有问题他也会在传输层中被识别出来再丢弃重传。)
- 32位源地址和32位目标地址: 表示发送端和接收端。
- 选项字段(不定长, 最多40字节): 略。
封装(首部长度一般也是20byte)和解包:因为有首部长度和总长度,所以提取有效载荷就是总长度减去首部长度。
分用:对应的对端收到报头,提取前20字节,然后解包,再找到8位协议(发送时会填充是什么协议发送的数据),看里面是TCP/UDP,然后就把数据交给上层对应的TCP/UDP缓冲区,就拿到数据了。分片例子 :应用层给了2980数据(假设一下最多传1500的数据)
分片的时候 : 20 + 1480 --1500
20 +1480 --1500
20 +20 --- 40
也就是说网络层的 报头也当成了数据传过去(传输层给的数据只有2980,加上报头20就是3000)13位偏移分别是 0 1500 2960
分片对UDP和TCP有影响吗?
统一的影响都是增加了丢包概率(因为分片数据丢的可能更大嘛),对TCP影响不大,因为tcp有可靠性(重传),但是udp影响大了,因为他是不可靠的,如果分片丢包,那么会直接影响到udp。所以一般不建议分片,但是分片的方案非常优秀,他只用了三个字段就完成了分片和组装的功能,值得学习借鉴。
那么如何做到减少分片呢?
首先,网络层是否分片是由网络层决定的吗?不,是传输层决定的(传的数据的多少),所以传输层不仅仅考虑对方接受能力和网络拥塞的问题,还要考虑数据链路层的传输大小。总结:
记住IP是提供数据从一端传输给另一端的能力,并不是100%成功传输,而TCP是提供的策略,使数据能100%传输给另一端!
网段划分(重要)
IP 地址分为两个部分 , 网络号和主机号 网络号 : 保证相互连接的两个网段具有不同的标识 ; 主机号 : 同一网段内 , 主机之间具有相同的网络号 , 但是必须有不同的主机号 ; (1.IP构成:目的网络+目的主机)IP地址是四字节的(FF代表一个字节),不要把IP看成一个整体,前三个是目的网络,最后面是目的主机。
网段:网络标识相同主机的聚合。
路由器:负责在不同网段之间进行数据转发。(前提就是集联两个不同的网络,所以路由器最少要有两个不同的网络接口,配上不同的IP地址(不同的网卡))
即在网络发送时,发现并不是本身网络标识,就会把数据发给路由器,路由器就有较大的概率继续向后转发。
2.网段划分:既然我们现在能用IP,那么肯定是曾经已经有角色已经将我们全球的IP进行过地址划分(和我们用学号一样) 不同的子网其实就是把网络号相同的主机放到一起。 如果在子网中新增一台主机 , 则这台主机的网络号和这个子网的网络号一致 , 但是主机号必须不能和子网中的其他主机重复。通过合理设置主机号和网络号, 就可以保证在相互连接的网络中, 每台主机的IP地址都不相同. 那么问题来了, 手动管理子网内的IP, 是一个相当麻烦的事情.
有一种技术叫做 DHCP, 能够自动的给子网内新增主机节点分配 IP 地址 , 避免了手动管理 IP 的不便。 一般的路由器都带有 DHCP 功能 . 因此路由器也可以看做一个 DHCP 服务器。过去曾经提出一种划分网络号和主机号的方案, 把所有IP 地址分为五类, 如下图所示(该图出 自[TCPIP])。
A 类 0.0.0.0 到 127.255.255.255 B 类 128.0.0.0 到 191.255.255.255 C 类 192.0.0.0 到 223.255.255.255 D 类 224.0.0.0 到 239.255.255.255 E 类 240.0.0.0 到 247.255.255.255 随着 Internet 的飞速发展 , 这种划分方案的局限性很快显现出来 , 大多数组织都申请 B 类网络地址 , 导致 B 类地址很快就分配完了, 而 A 类却浪费了大量地址; 例如 , 申请了一个 B 类地址 , 理论上一个子网内能允许 6 万 5 千多个主机 . A 类地址的子网内的主机数更多。 然而实际网络架设中 , 不会存在一个子网内有这么多的情况 . 因此大量的 IP 地址都被浪费掉了。 目前我们已经不按这种分类划分的方式来划分IP了,而采用子网掩码的方式了,子网掩码一般配置进特定的路由器当中,路由器会按照子网掩码按位与运算来确定你要去的目标主机。针对这种情况提出了新的划分方案, 称为CIDR(Classless Interdomain Routing):
引入一个额外的子网掩码 (subnet mask) 来区分网络号和主机号 ; 子网掩码也是一个 32 位的正整数 . 通常用一串 "0" 来结尾 ; 将 IP 地址和子网掩码进行 " 按位与 " 操作 , 得到的结果就是网络号 ; 网络号和主机号的划分与这个IP地址是A类、B类还是C类无关 ;下面有两个例子:
可见 ,IP 地址与子网掩码做与运算可以得到网络号 , 主机号从全 0 到全 1 就是子网的地址范围 ; IP 地址和子网掩码还有一种更简洁的表示方法 , 例如 140.252.20.68/24, 表示 IP 地址为 140.252.20.68, 子网掩码的高24位是 1, 也就是 255.255.255.0 IP也是资源,在国家层面也在竞争 假设我们国家IP是11开头,当有一个10开头的数据时就发现不是我们子网的IP,就根据我们国家的 出口路由器把这个报文查他的路由表转发到美国的路由表,然后在美国的内网进行转发(我们内就按省市县再分子网类推)。 三大运营商搞基础设施:
国家在拿到IP地址后,就交给三大运营商去搞基础设施,硬件上光纤光缆,基站,大型机房,工业级的路由器交换机。 所以再看这个,就是根据这样的网段划分,在全球中把IP分给其他人,但是这样的划分方式,有的主机号/网络号用不完,就用了子网掩码来防止/减少浪费。 主机号的数量就是2的主机号的次方-2
为什么主机号-2?
当主机号全0发现就是网络号(按位与后就是全0)
全1其实是局域网内的广播地址也不能被使用
所以-2。
(子网地址范围就是可以有多少台主机)
(网段划分其实就是分分配IP资源的一种策略)
为什么要进行子网划分?
因为经过子网划分可以大大提高我们的查找效率(发送谋数据时,可以通过前面的几个比特位,确定他所在的地区,一次排除一大批子网区域) 域名解析(网络层的 ICMP 协议)
但是平时我们都是通过域名去访问的,全球上就有一个组织进行域名解析,做域名和IP的映射,访问时先请求域名解析,然后返回对应IP,然后使用的人他的客户端再去用IP进行访问。特殊的IP地址
将 IP 地址中的主机地址全部设为 0, 就成为了网络号 , 代表这个局域网 ; 将 IP 地址中的主机地址全部设为 1, 就成为了广播地址 , 用于给同一个链路中相互连接的所有主机发送数据包; 127.* 的 IP 地址用于本机环回 (loop back) 测试 , 通常是 127.0.0.1;loopback设备
IP地址的数量限制
我们知道 , IP 地址 (IPv4) 是一个 4 字节 32 位的正整数 . 那么一共只有 2 的 32 次方 个 IP 地址 , 大概是 43 亿左右 . 而 TCP/IP协议规定, 每个主机都需要有一个 IP 地址。 这意味着 , 一共只有 43 亿台主机能接入网络么 ? 实际上 , 由于一些特殊的 IP 地址的存在 , 数量远不足 43 亿 ; 另外 IP 地址并非是按照主机台数来配置的 , 而是每一个网卡都需要配置一个或多个IP 地址。 CIDR 在一定程度上缓解了 IP 地址不够用的问题 ( 提高了利用率 , 减少了浪费 , 但是 IP 地址的绝对上限并没有增加 ), 仍然不是很够用. 这时候有三种方式来解决: 动态分配 IP 地址 : 只给接入网络的设备分配 IP 地址 . 因此同一个 MAC 地址的设备 , 每次接入互联网中 , 得到的IP 地址不一定是相同的 ; NAT技术 ( 后面会重点介绍 ); IPv6: IPv6 并不是 IPv4 的简单升级版 . 这是互不相干的两个协议 , 彼此并不兼容 ; IPv6 用 16 字节 128 位来表示一个IP 地址 ; 但是目前 IPv6 还没有普及 ;私有IP地址和公网IP地址
IP地址除了自身构成上被分成目的IP和目标主机,在整体的结构上也被拆分成私有IP地址和公网IP地址。有一些IP地址是不能放在公网上的,只能用于组建局域网或者组建子网,这样的IP我们称为私有IP,除了私有IP其他的才能出现在公网上。
如果一个组织内部组建局域网 ,IP 地址只用于局域网内的通信 , 而不直接连到 Internet 上 , 理论上 使用任意的 IP 地址都可以, 但是 RFC 1918 规定了用于组建局域网的私有 IP 地址 10.*, 前 8 位是网络号 , 共 16,777,216 个地址; 172.16. 到 172.31. , 前 12 位是网络号 , 共 1,048,576 个地址; 192.168.*, 前 16 位是网络号 , 共 65,536 个地址; 包含在这个范围中的 , 都成为私有 IP, 其余的则称为全局 IP( 或公网 IP);
- 一个路由器可以配置两个IP地址, 一个是WAN口IP, 一个是LAN口IP(子网IP)。
- 路由器LAN口连接的主机, 都从属于当前这个路由器的子网中。
- 不同的路由器, 子网IP其实都是一样的(通常都是192.168.1.1). 子网内的主机IP地址不能重复. 但是子网之间的IP地址就可以重复了。
- 每一个家用路由器, 其实又作为运营商路由器的子网中的一个节点. 这样的运营商路由器可能会有很多级,最外层的运营商路由器, WAN口IP就是一个公网IP了。
- 子网内的主机需要和外网进行通信时, 路由器将IP首部中的IP地址进行替换(替换成WAN口IP), 这样逐级替换, 最终数据包中的IP地址成为一个公网IP. 这种技术称为NAT(Network Address Translation,网络地址转换)。
- 如果希望我们自己实现的服务器程序, 能够在公网上被访问到, 就需要把程序部署在一台具有外网IP的服务器上. 这样的服务器可以在阿里云/腾讯云上进行购买。
那么私有IP如何解决我们IP不足的呢?
首先,家里想要上网:就是把要运营商把网线拉到家里面。
第二个就是我们平时使用APP,是APP给我们提供服务,但是我们提供服务,但是交话费是交给三大运营商呢?
那就是家用路由器除了有IP报文转发的功能外,还有一个功能就是构建子网(构建子网可是应用层做的事情,路由器他也能搞定)。路由器这个设备通常是叫做一号主机,比如你的IP是192.168.3.10那么你家里的路由器IP大概是192.168.3.1。
因为家用路由器是构建的局域网,所以只能用私有IP。
即:我家里的路由器构建的私有IP和你家路由器构建的私有IP可以是完全一样的。(因为他不会出现在公网上,是私有IP,所以我们称他为局域网,而在局域网之间的主机是可以直接通信的)那么如果我家里想要上网的话,那么家里的路由器对外上网时并不是直接通过家用路由器到达公网了(他做不到),而是家里的路由器把数据推送给运营商的路由器/运营商在某个市内或者省内搭建好的路由集群到达运营商的机房里,帮你做转发,然后运营商把你的数据再交给公网,在公网当中帮你请求对应的某些服务。(换句话说,我们的家用路由器并不是直接访问公网,而是通过运营商再去访问公网的)
那么为什么要经过运营商呢?
因为家里的网是通过运营商拉的,网线去找,就一定能找到运营商对应的机房/集群/基站之类的,换言之,运营商把网线拉到我们家里面,那么数据出去的时候也一定会经过运营商,即家用路由器不能直接绕过运营商,到达公网。家用路由器有两套密码:
第一套就是自己设置的wifi密码。
第二套就是路由器内部可以通过浏览器去访问,他有IP地址,所以你是可以直接访问路由器的IP地址的,访问到之后会有一个网页,是可以配置路由器的,比如限制你家里路由器可连接手机电脑的个数,包括上行/下行的速度。还有一个配置就是路由器内部的账号和密码,比如说这个网是拿你的手机号弄的,那他的账号就是你的手机号,密码是自己设置的,这个账号和密码是配置好的,往后家里网没钱了就可以拿着手机去交网费,你的数据包再发出去的时候,运营商就识别到当你想上网时,他要先对你做认证,认证你有没有交过钱,怎么认证交期呢,就是你家用路由器在刚开始访问时,家用路由器会自动把自己的账号信息和密码信息推送给运营商,运营商就拿着这个账号和密码去认证,这个人是否是合法的,及去查看运营商内部的缴费平台里,去认证这个用户现在的余额,是否允许上网,如果发现你交过费了,那么你发送到运营商的信息,他就正常替你转发了,如果没有,就在运营商的平面上,把你的数据直接丢弃,即你就上不了网了。但是注意,虽然欠费,但是是可以给运营商发消息的,这就是为什么平时手机欠费了上不了网了但依旧能打10086的原因。
所以家用路由器的两套密码,一个是保证你连上路由器,另一个是来认证的(是工作人员上门服务把账号和密码设置好)。但是现在又有问题的,我们现在是私有IP啊(有其他的人可能和我们IP相同,因为每个家用路由器都可以构建子网,子网上的IP大家可以是一样的),当公网IP收到我们消息,给我们发消息时,填目的IP难道是我们私有IP吗?又有那么多相同的怎么办呢?
所以我们为了保证私有IP不出现在公网上,同时消息可以推送回来,所以一般我们的路由器至少要有两个网口,一个是WAN口,一个是LAN口。家里的路由器,一方面连接的是我们家里的私网,另一方面是连接的运营商,而运营商内部自己构建的也是一个私网。
现在当我们的数据包想要转发出去(重要):
首先我们要出去的报文,src:201 dst:122(简单填一下),报文经过转发到达家用路由器,肯定是能到因为家用路由器的子网IP也叫做LAN口IP是192.168.1.1和我的192.168.1.201是在同一个网段的,即同一个局域网,而同一个局域网的两台主机可以直接通信。所以这个数据包就转给路由器了,家用路由器收到数据包时知道他是无法直接推送到公网的,他就会自动做一件事情,他就会把报文的LAN口(家用路由器的子网)IP,替换成路由器的WAN口IP,即现在报文的src:10.1.1.2,即报文目的IP不变,原IP变成了路由器的WAN口IP,这样家用路由器就替你把数据再进行转发(根据目的IP,发现IP肯定不是运营商内部的IP),就把数据转到了运营商上(运营商自己也是个私网,他也有自己的子网IP(LAN口IP)和WAN口IP),然后这个运营商服务器知道有个路由器给他发了消息,但是他的原IP依旧是私网IP,也不能用,就把当前报文的LAN口IP(src)替换成运营商的WAN口IP,现在报文的 src:122.77.241.4 dst:122,又现在该运营商路由器已经属于公网了,所以这个时候他再代你去访问APP,然后APP发现有人请求他了,他就返回报文(携带比如短视频),他的报头dst:122.77.241.4 src:122.77.241.3,目前IP是在公网上的,直接经过广域网传给我们的运营商的路由器。(目前我们就知道,局域网的数据,发送到公网,是需要不断替换原IP来完成的,这种技术就是NAT技术)
即现在我们有了这种原IP地址不断替换的做法,就可以大量构建局域网来使用我们的公网资源了!而且局域网IP是可以重复的,就相当于隐性增加了IP地址的数量!
数据如何回来:因为推送出去的时候,WAN口IP是不同的,哪怕你们的私网里面的IP相同,但是推送出去数据的时候,你们的WAN口IP不一样,那么回来的时候也就不同,然后根据你发送时的源IP再根据路由器转发,就可以接受到公网返回的数据了!
路由
在复杂的网络结构中 , 找出一条通往终点的路线 ; 路由的过程 , 就是这样一跳一跳 (Hop by Hop) " 问路 " 的过程。 所谓 " 一跳 " 就是数据链路层中的一个区间 . 具体在以太网中指从源 MAC 地址到目的 MAC 地址之间的帧传输区间。 当我们进行路由的时候,先将数据路由,根据IP地址(IP地址被分为两块,一部分为目标网络,一部分为目标主机),所以当报文在路上传送的时候(路由器拿着你的IP报文里面取目的IP与自身子网掩码做按位与,然后拿着目标网络在自己路由器内部的路由表进行查找,路由器将会决定将这个数据直接转发给下一跳或者默认路由或者目标主机这样的过程),先根据目的网络先将数据先送到目标网络,然后在目标网络内根据IP的目标主机进行内网转发,将数据发送到目标主机,这就是他路由的过程。IP数据包的传输过程也和问路一样。
当 IP 数据包 , 到达路由器时 , 路由器会先查看目的 IP; 路由器决定这个数据包是能直接发送给目标主机 , 还是需要发送给下一个路由器 ; 依次反复 , 一直到达目标 IP 地址 ;那么如何判定当前这个数据包该发送到哪里呢? 这个就依靠每个节点内部维护一个路由表;
路由表可以使用route命令查看;
如果目的 IP 命中了路由表 , 就直接转发即可 ; 路由表中的最后一行以上是关于网络层协议 IP的主要内容,如果未能解决你的问题,请参考以下文章