【Linux】网络编程 —— 网络层 IP协议 📅 2026/8/23 8:46:52 欢迎来到Linux专栏 ~~ 网络编程博客主页张小姐的猫~江湖背景所属专栏Linux ~ 不破不立作者水平很有限如果发现错误可在评论区指正感谢网络编程 ~ IP协议欢迎来到Linux专栏 ~~ 网络编程基本概念和协议头格式网段划分重点私有IP地址和公IP地址✅尝试理解公网路由⚙️IP分片和组装的具体过程分片与组装的过程写在最后网络层在复杂的网络环境中确定⼀个合适的路径基本概念和协议头格式基本概念主机配有IP地址也要进行路由控制的设备路由器即配有IP地址又能进行路由控制路由器也是主机节点主机和路由器的统称但是为了表述方便我就把两端的叫主机路径上的都叫做节点1️⃣初步理解IP的作用主机是根据报文中的目的IP进行路径选择2️⃣IP地址的构成 — 路由查找目标主机的一般方法是什么IP地址 目标网络 目标主机类似于学号 学院号 班级班 个人号3️⃣TCP IPIP协议提供了一种能力把数据包从主机A跨网络进过路径选择路由转发发送到主机B的能力—— 有能力不代表 百分百能做到极大概率能做成那么网络不要有任何差错需要的是可靠性于是TCP就是来保证可靠性的。所以TCPIP保证数据包可靠地发送到目的地协议头格式4位版本号(version)指定IP协议的版本对于IPv4来说就是44位头部长度IP头部的长度是多少个32bit也就是length * 4的字节数。4bit表示最大的数字是15因此IP头部最大长度是60字节8位服务类型3 位优先权字段(已经弃用)4位TOS字段和1位保留字段(必须置为0)。4位TOS分别表示最小延时最大吞吐量最高可靠性最小成本。这四者相互冲突,只能选择⼀个对于ssh/telnet这样的应用程序最小延时比较重要对于ftp这样的程序最大吞吐量比较重要16位总长度IP数据报整体占多少个字节8位生存时间数据报到达目的地的最大报文跳数。⼀般是64。每次经过⼀个路由TTL减1一直减到0还没到达那么就丢弃了。这个字段主要是用来防止出现路由循环8位协议表示上层协议的类型交给tcp还是udp—— 发送方来填肯定知道有效载荷是谁给它的32位源地址和32位目标地址表示发送端和接收端最下方的数据要进程传输的数据包站在接收方视角看1️⃣IP报头和有效载荷如何分离标准报头长度是20字节sk_buff指针移动也有4位首部长度取数据时乘它存数据是除它—— 20 ~ 6016位总长度记录了整个报文的长度2️⃣有效载荷分用法的问题3️⃣网段划分重点IP地址分为两个部分网络号和主机号网络号保证相互连接的两个网段具有不同的标识主机号同⼀网段内主机之间具有相同的网络号但是必须有不同的主机号路由器有一个核心功能构建子网局域网不同的子网其实就是把网络号相同的主机放到⼀起如果在同一个子网中新增⼀台主机则这台主机的网络号和这个子网的网络号⼀致但是主机号必须不能和子网中的其他主机重复通过合理设置主机号和网络号就可以保证在相互连接的网络中每台主机的IP地址都不相同那么问题来了手动管理子网内的IP是⼀个相当麻烦的事情有⼀种技术叫做DHCP能够自动的给子网内新增主机节点分配IP地址避免了手动管理IP的不便⼀般的路由器都带有DHCP功能。因此路由器也可以看做⼀个DHCP服务器过去曾经提出⼀种划分网络号和主机号的方案把所有IP地址分为五类如下图所示 ———划分网段A类0.0.0.0到127.255.255.255B类128.0.0.0到191.255.255.255C类192.0.0.0到223.255.255.255D类224.0.0.0到239.255.255.255E类240.0.0.0到247.255.255.255随着Internet的飞速发展这种划分方案的局限性很快显现出来大多数组织都申请B类网络地址导致B类地址很快就分配完了而A类却浪费了大量地址IP地址使用不充分是谁在申请网络地址呢针对这种情况提出了新的划分方案称为CIDR(ClasslessInterdomainRouting)(无类别域间路由)引入⼀个额外的子网掩码(subnetmask)来区分网络号和主机号 —— 设置在路由器内部子网掩码也是⼀个32位的正整数。通常用⼀串0来结尾将IP地址和子网掩码进行按位与操作得到的结果就是网络号网络号和主机号的划分与这个IP地址是A类、B类还是C类无关注意子网掩码和分类划分是同时存在的二者并不冲突子网划分的本质从主机号中借若干位作为子网号用更长的子网掩码来区分不同的子网。借的位越多子网数量越多但每个子网的主机数越少——这是一个此消彼长的关系主机号为0140.252.20.0通常代表的就是网络的地址❌️不去考虑不分配给某一台主机主机号为全1代表广播地址不分配给某一台主机。也就是说例1里可分配的主机数是254例二计算如下算出有16台主机真正能用的16 - 2 14台。可见IP地址与子网掩码做与运算 可以得到网络号主机号从全0到全1就是子网的地址范围IP地址和子网掩码还有⼀种更简洁的表示方法例如140.252.20.68/24表示IP地址为140.252.20.68子网掩码的高24位是1也就是255.255.255.0为什么要进行网段划分举个例子以学校为例每个院都有自己的院号方框是学校群把每个院的学生会主席都拉群现在发现了一个丢失的钱包里面只有一张学生证只能看得见学号 —— 如何归还钱包呢那我们也不知道学号是对应了什么呀 我只知道我们计算机院的院号是0106是哪个院呢只能告诉院学生会主席最后通知机械院的学生会主席来进行联系失者张三就是源主机目的IP是06321目的主机是丢失者☀️为什么要进行网络划分呢把报文交给目标主机的本质是查找工作♦️查找的本质是淘汰为了支持未来查找时的快速淘汰 大大提高查找效率当张三发现0631不是本院的就已经淘汰了一个院的学生了后续交给机械学院后本质就已经淘汰了剩余的学院 —— 只交给了机械学院如果是127.*开头的地址就会直接放入到一个环回驱动程序里后续再拿走接着我们来看看IP地址的数量限制我们知道IP地址(IPv4)是⼀个4字节32位的正整数。那么⼀共只有2的32次⽅个IP地址大概是43亿左右。而TCP/IP协议规定每个主机都需要有⼀个IP地址这意味着一共只有43亿台主机能接入网络么?实际上,由于⼀些特殊的IP地址的存在数量远不足43亿全0 / 全1 / 127*另外IP地址并非是按照主机台数来配置的而是每⼀个网卡都需要配置⼀个或多个IP地址CIDR子网划分在⼀定程度上缓解了IP地址不够⽤的问题(提高了利用率减少了浪费但是IP地址的绝对上限并没有增加)仍然不是很够用。这时候有三种方式来解决:动态分配IP地址只给接入网络的设备分配IP地址。因此同⼀个MAC地址的设备每次接入互联网中得到的IP地址不⼀定是相同的不就就还给路由器路由器接着下次进行分配NAT技术IPv6IPv6并不是IPv4的简单升级版。这是互不相干的两个协议彼此并不兼容IPv6用16字节128位来表示⼀个IP地址但是目前IPv6还没有普及内网普及了公网没有私有IP地址和公IP地址如果一个组织内部组建局域网IP地址只用于局域网内的通信而不直接连到Internet上理论上使用任意的IP地址都可以但是RFC1918规定了用于组建局域网的私有IP地址10.*前8位是网络号共16,777,216个地址172.16.*到172.31.*前12位是网络号共1,048,576个地址192.168.*前16位是网络号共65,536个地址包含在这个范围中的都成为内网IP其余的则称为全局IP(或公网IP)路由器是组建内网的设备给所有链接这个路由器的机器分配IP地址先来认识一下运营商为什么我们每个月要交话费给运营商呢 为什么不是交给抖音B站因为要通过运营商建立的光纤、机房等没有这些基础工作根本无法连接到服务器下面来正式说NAT网络地址转化LAN口对内子网IP因为掩码是24所以子网开头是以192.168.1开头WAN口对外链接的是运营商运营商也能构建一个更大的子网细节1️⃣我们所有人都不可以直接连接公网都是通过先连接到局域网中通过局域网接入公网的细节2️⃣私有IP是可以重复的但是公网IP不能私有IP地址可以重复但不影响上网的话不就增加了IP地址的绝对上限吗IP不足的问题就被大大缓解了把报文发出到公网里发现不属于本网络的话继续向上交付WAN口都发给能向外访问的路由器如果服务器要把数据发回去呢dst192.168.1.201src122.77.241.3data:lbwnb这个时候发现有问题了因为私有IP是可以重复的是把这个报文传给哪个主机呢 ——这个报文怎么回来呢接下来我们看看真实情况是怎样的 ————报文每经过一个路由器路由器就会自动把报文的SRC换成自己的WAN口IP内网到公网的过程中途经路由器都会雁过拔毛替换src ip 变成自己的wan口IP ——公网内就不会替换这个替换只在内网转发进行回去的报文来到运营商服务器 后续如何继续转发到家庭路由器暂时先不讲后续内网穿刺详解我们来理解这个现象我们所有人都在局域网中本机的ip地址在登录到服务器去查看发现并不是本机的ip地址说明发生了转化了最终服务器上显示的ip地址是入公网路由器的WAN口IP地址这个现象本质还是在解决IP地址不足的问题IP地址的消耗真正在广域网上内网IP不算真正的消耗比如说一个小米鱼缸也会有自己的IP地址但是属于内网的IP不是真正的消耗IPIPV4一共就42亿个经不起这样的折腾总结⼀个路由器可以配置两个IP地址⼀个是WAN口IP对外⼀个是LAN口IP(子网IP)路由器LAN口连接的主机都从属于当前这个路由器的子网中不同的路由器子网IP其实都是⼀样的(通常都是192.168.1.1)。子网内的主机IP地址不能重复。但是子网之间的IP地址就可以重复了每⼀个家用路由器其实又作为运营商路由器的子网中的一个节点。这样的运营商路由器可能会有很多级最外层的运营商路由器WAN口IP就是⼀个公网IP了子网内的主机需要和外网进行通信时路由器将IP首部中的IP地址进行替换(替换成WAN口IP)这样逐级替换最终数据包中的IP地址成为⼀个公网IP。这种技术称为NAT(NetworkAddressTranslation网络地址转换).✅尝试理解公网真实的网络结构非常复杂即涉及到划分公网IP的组织ICANN还要在全球范围内进行区域划分比如亚太北美欧洲等又要考虑各个国家内部的ISP代理整体拓扑非常复杂我们简化所有过程简单理解公网即可接下来我们简单理解一下数据是怎么由一个国家传到另一个国家的如果河北路由器收到了一个报文是5.1.0.100立马拿到这个地址和子网掩码进行按位与发现这个报文是要去澳门的就把该报文通过国内骨干网络转发到对应的下一跳地址也就是每个省份的路由器都会直到全国范围内的网络地址的 —— 查路由表把报文地址与子网掩码进行按位与逐个的对比查表。拿国际路由举例路由表中不止有网络中其他国家的的网络地址还有各省份的网络地址—— 每个省份路由一旦上线就会进行广播通告通过路由表交换算法把自己的网络地址、子网掩码、下一跳地址等等都告诉对方其中西安的WAN地址5.1.16.1 / 20说明 0000 0000 8位中只拿了4个比特位来进行市级别的划分所以掩码是256.256.240.0此处引出了默认路由一旦查路由查不到就交给对应的默认路由路由在复杂的网络结构中找出⼀条通往终点的路线每一个路上节点都要包含一个路由表根据目的IP和子网掩码查表的过程就是路由所谓一跳就是数据链路层中的一个区间。具体在以太网中指从源MAC地址到目的MAC地址之间的帧传输区间路由的过程就类似于现实中问路的过程我不知道怎么走 但是那边的阿姨知道 ——默认路由配的一般是出口是另一个更高级的路由告诉你下一步的地址去哪乘车——查到了路由条目得知下一跳的地址了我不知道IP数据包的传输过程也和问路一样当IP数据包到达路由器时路由器会先查看目的IP路由器决定这个数据包是能直接发送给目标主机还是需要发送给下⼀个路由器;依次反复⼀直到达目标IP地址那么如何判定当前这个数据包该发送到哪里呢这个就依靠每个节点内部维护⼀个路由表路由表可以使用route命令查看如果目的IP命中了路由表就直接转发即可路由表中的最后一行主要由下⼀跳地址和发送接口两部分组成当目的地址与路由表中其它行都不匹配时就按缺省路由条目规定的接口发送到下⼀跳地址假设某主机上的网络接口配置和路由表如下:这台主机有两个网络接口⼀个网络接口连到192.168.10.0/24网络另⼀个网络接口连到192.168.56.0/24网络路由表的Destination是目的网络地址Genmask是子网掩码Gateway是下⼀跳地址Iface是发送接口Flags中的U标志表示此条目有效G标志表示此条目的下一跳地址是某个路由器的地址没有G标志的条目表示目的网络地址是与本机接口直接相连的网络不必经路由器转发转发过程例1如果要发送的数据包的目的地址是192.168.56.3跟第一行的子网掩码做与运算得到192.168.56.0与第⼀行的目的网络地址不符再跟第二行的子网掩码做与运算得到192.168.56.0正是第二行的目的网络地址,因此从eth1接口发送出去由于192.168.56.0/24正是与eth1接口直接相连的网络因此可以直接发到目的主机不需要经路由器转发因为没有G标志转发过程例2如果要发送的数据包的目的地址是202.10.1.2依次和路由表前几项进行对比发现都不匹配按缺省路由条目从eth0接口发出去发往192.168.10.1路由器由192.168.10.1路由器根据它的路由表决定下⼀跳地址⚙️IP分片和组装的具体过程先来由滑动窗口引出 —— 为什么滑动窗口内可直接发给对方的字节数不能次发完4000呢而是每次只发1000呢数据会经过网络层交给数据链路层在数据链路层要求它的有效载荷长度不能超过MTU最⼤传输单元一般是1500字节也就是说数据链路层只能接收1500字节大小超过的话自己进行切片分好再给我 ——数据链路层不负责拆分必须要由网络层来拆分谁分片就谁进行组装但是不建议过多的分片和组装的并不是我们真实的网络通信的普世情况如果分成了四片进行发送呢站在对方的传输层来说就会认为你的报文校验和失败报文不完整 相当于整体丢包了—— 要求对方进行快重传、超时重传再发一次不建议分片的理由慢增加了丢包概率。报文分成了四片的话任意一个报文丢了这个报文就算丢了如果传输层传过来的数据很大才导致网络层要进行分片的网络层是不能控制发过来的数据大小的 —— 于是向上传话给传输层让它每次少发一点于是传输层就会一小段的发报文所以就是我们看见的每次发1000就可以有效的减少网络层的分片操作如果tcp和IP的报头都是20字节的话导致最后的有效载荷变成了1460的大小其实在三次握手的时候就会交换双方的MSG最大段尺寸分片与组装的过程我们着重的来讲组装的过程16位标识(id)唯⼀的标识主机发送的报文。如果IP报文在数据链路层被分片了那么每⼀个片里面的这个id都是相同的3位标志字段第一位保留(现在不用但是还没想好说不定以后要用到)。第二位置为1表示禁止分片这时候如果报文长度超过MTUIP模块就会丢弃报文。第三位表示更多分片如果分片了的话最后⼀个分片置为0其他是1。类似于一个结束标记.只有最后一个片的置0在此前面的都是113位分片偏移是分片相对于原始IP报文开始处的偏移。其实就是在表示当前分片在原报文中处在哪个位置。注意片偏移(13位)表示本片数据在它所属的原始数据报数据区中的偏移量以8字节为单位⚽️分片组装分完片后的每一片都会有IP报头的所以说分片分的是有效载荷1️⃣识别出来报文是否被分片了每个一个报文没有被分片其MF标志位 0片偏移量等于 0—— 说明只有一片相反的只要其MF标志位 0||片偏移量不等于 0说明是一定被分片了2️⃣怎么样把分片给聚合在一起哪里是结尾、开头、怎么聚合开头片的片偏移是为0结尾片的MF是 0、对于中间的片自己的片偏移 自身长度 下一片的片偏移—— 不就可以对收到的所有分片按照片偏移来进行升序排序那怎么保证报文收全了呢通过16位标识将报文聚合在一起对偏移量进行升序排序如果出现一个分片的片偏移是200前一片的偏移是100自身长度为20下一个分片的偏移应该是120与200不相符所以就说明分片并没有收全这样一通操作下来不就是组装的过程了吗分片组装过程假设在IP层有⼀个大小为3000字节的报文如何分片如何组装呢写在最后接下来登场的是 HTTP