C类地址201.222.5.0/24切20个子网:/29掩码推导与工具对账
简介:这份实验报告面向计算机网络课程学习者与任课教师,围绕子网划分这一核心技能展开,可用于课堂实验、上机作业参考或期末复习。报告以C类地址201.222.5.0划分20个子网、每个子网约5台主机为具体案例,完整记录了实验目的与要求、实验环境与方案设计、基于HA_subnet10、子网计算工具1.1与子网掩码计算器三种工具的求解步骤,并附有关于子网划分作用、子网掩码作用的两道思考题及参考答案,以及学生心得体会,便于读者对照理解手工计算与工具验证的差异,掌握子网掩码、子网号、广播地址与主机范围的推导思路。资源为1个doc文档,压缩包约42KB,篇幅精炼、结构按实验报告规范组织,适合直接套用格式或按步骤复现实验。目前已有1995人学习,可作为子网划分入门的轻量参考材料。
1. 一份 C 类地址要切 20 个子网:201.222.5.0/24 到底该怎么下刀
子网划分这道题,很多人不是不会算,而是算完心里没底。手上这份《实验报告 4 子网的划分》正好把一道典型的 C 类地址切分题摊开了:给定 201.222.5.0,要求切出 20 个子网、每个子网 5 台主机,先手工推出子网掩码、子网号、广播地址和主机范围,再用 HA_subnet10、子网计算工具 1.1、子网掩码计算器三款工具各跑一遍对账。它适合正在啃计算机网络实验、被借位和掩码绕晕的人,也适合要给新人做入门材料的人。真正值钱的地方是它逼你把同一道题算四遍——手工一遍、工具三遍,哪一步错了当场就暴露,比看十页理论管用。
2. 先把位数算清楚:20 个子网与 5 台主机的双边约束
2.1 两个不等式一起解,别只盯着一个
C 类地址的默认掩码是 255.255.255.0,前缀 /24,第四字节 8 位全部留给主机。要划分子网,就是从这 8 位里从高位借 n 位当子网位,剩下 h = 8 - n 位当主机位。约束是两条:
- 子网数:2^n ≥ 需求子网数(现代设备支持全 0 和全 1 子网,直接按 2^n 算;老教材按 2^n - 2 算,这一步差异后面会专门讲)
- 每子网可用主机数:2^h - 2 ≥ 需求主机数(减 2 是网络地址和广播地址不能分配给主机)
代入本题:2^n ≥ 20,n = 4 时只有 16 个,不够;n = 5 时 32 个,够。2^h - 2 ≥ 5,h = 2 时只有 2 台,不够;h = 3 时 6 台,够。
关键在于 5 + 3 = 8,正好把 C 类的 8 位主机位用满,一位不剩。这不是巧合,是出题人故意设计的——两边同时卡死,答案唯一,就是 /29。如果题目改成「20 个子网、每子网 30 台主机」,那就无解了:借 5 位只剩 3 位主机,最多 6 台;借 4 位只有 16 个子网。这时候只能换更大的地址块或者上 VLSM。看懂这个「刚好卡死」,你就知道为什么这道题值得反复做。
2.2 从借位数推到点分十进制掩码
算出 n = 5 之后,掩码的推导是机械的。前 24 位全 1,第四字节前 5 位为 1、后 3 位为 0:
第四字节:1111 1000 二进制转十进制:128 + 64 + 32 + 16 + 8 = 248所以子网掩码是 255.255.255.248,前缀写作 /29。反过来验算:256 - 248 = 8,这就是块大小,也就是相邻两个子网网络地址之间的间隔。
把常见的几档列出来对照,选型时直接查表比现算快:
| 借位数 n | 前缀 | 点分十进制掩码 | 子网总数 | 剩余主机位 h | 每子网可用主机 |
|---|---|---|---|---|---|
| 0 | /24 | 255.255.255.0 | 1 | 8 | 254 |
| 2 | /26 | 255.255.255.192 | 4 | 6 | 62 |
| 3 | /27 | 255.255.255.224 | 8 | 5 | 30 |
| 4 | /28 | 255.255.255.240 | 16 | 4 | 14 |
| 5 | /29 | 255.255.255.248 | 32 | 3 | 6 |
| 6 | /30 | 255.255.255.252 | 64 | 2 | 2 |
这张表要能背下来。/28 那一行是本题最常见的错误答案——16 个子网不满足 20 个的需求,但很多人一看到「二十来个」就条件反射填 240,翻车就翻在这里。
2.3 二进制视角:块大小 8 是怎么来的
把 201.222.5.0 的第四字节写成二进制:0000 0000。加上 /29 掩码1111 1000之后,前 5 位是子网位,后 3 位是主机位。
主机位 3 位意味着每个子网内部能表示 2^3 = 8 个地址,从全 0 到全 7。全 0 那个是网络地址,全 1 那个是广播地址,中间 6 个才是可用主机。这就是块大小 8 的来源,也是「子网号之间差 8」的来源。
换个角度理解:掩码末尾有几个 0,块大小就是 2 的几次方。末尾 3 个 0 → 8。这条规律在 /25 到 /30 之间全部成立,口算时非常顺手。比如 /27 末尾 5 个 0 → 块大小 32,子网就是 .0、.32、.64、.96……一眼就能报出来。
实验报告里那道思考题「子网掩码的作用是什么」,标准答案写「区分网络位和主机位」没错,但落到工程上更实用的说法是:掩码告诉你两件事——网络地址的步长是多少(块大小),以及哪些地址不能分给设备(网络地址和广播地址)。这两件事决定了你配置 IP 时的合法区间,比抽象定义有用得多。
3. 手工算一张全表:子网号、广播地址、主机范围的推演
3.1 以 8 为步长枚举 32 个子网
既然块大小是 8,第四字节的子网起点就是 0、8、16、24、32、40……248,一共 32 个。每个子网的三个关键地址这样定:
- 网络地址 = 起点本身(主机位全 0)
- 广播地址 = 起点 + 7(主机位全 1)
- 可用主机范围 = 起点 + 1 到 起点 + 6
把前几个和最后几个列出来,中间的自然就能推:
| 子网序号 | 网络地址 | 首个可用主机 | 末个可用主机 | 广播地址 |
|---|---|---|---|---|
| 1 | 201.222.5.0 | 201.222.5.1 | 201.222.5.6 | 201.222.5.7 |
| 2 | 201.222.5.8 | 201.222.5.9 | 201.222.5.14 | 201.222.5.15 |
| 3 | 201.222.5.16 | 201.222.5.17 | 201.222.5.22 | 201.222.5.23 |
| 4 | 201.222.5.24 | 201.222.5.25 | 201.222.5.30 | 201.222.5.31 |
| … | … | … | … | … |
| 20 | 201.222.5.152 | 201.222.5.153 | 201.222.5.158 | 201.222.5.159 |
| … | … | … | … | … |
| 32 | 201.222.5.248 | 201.222.5.249 | 201.222.5.254 | 201.222.5.255 |
第 20 个子网是本题必须单独验算的一个,因为需求正好是 20,边界感最强。计算方式是 (20 - 1) × 8 = 152,所以网络地址 201.222.5.152,广播 201.222.5.159,可用主机 153 到 158 共 6 个,刚好满足「每个子网 5 台主机」并留一个余量。
最后一个子网的广播地址 201.222.5.255 正好是整个 /24 网段的广播地址,这一点常被误认为是「地址被浪费了」,其实不是——/24 被完整切成 32 个 /29,没有留下任何缝隙,192 个可用主机地址一个不多一个不少。
3.2 拿第 1 个和第 20 个做双向验算
手工算完别急着抄进报告,用两个方向各验一遍。
正向验:网络地址 201.222.5.152,掩码 /29,求广播地址。把 152 写成二进制1001 1000,主机位是低 3 位000,全部置 1 得1001 1111= 159,广播地址 201.222.5.159。可用主机数 2^3 - 2 = 6。对上了。
反向验:如果某台主机配置成 201.222.5.158/29,它的网络地址是多少?158 的二进制1001 1110,与掩码1111 1000做按位与,低 3 位清零得1001 1000= 152。所以网络地址是 201.222.5.152,和正向算的完全一致。
反向验算是排错时最有用的动作。现场遇到「这台机器 ping 不通同网段的另一台」,第一步就是把两边 IP 各自和掩码按位与,看网络地址是不是同一个。不是同一个,路由配得再对也没用。
3.3 用位运算复核,不靠记忆
手工表最怕记错一位。写几行代码把按位与、按位或的逻辑跑一遍,比反复检查草稿纸靠谱:
def ip_to_int(ip: str) -> int: """把点分十进制转成 32 位整数,方便做位运算""" parts = [int(x) for x in ip.split(".")] return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3] def int_to_ip(n: int) -> str: """整数还原成点分十进制,每 8 位取一次""" return ".".join(str((n >> s) & 0xFF) for s in (24, 16, 8, 0)) mask = ip_to_int("255.255.255.248") # /29 掩码 host = ip_to_int("201.222.5.158") # 待验证的主机地址 network = host & mask # 按位与:主机位清零,得网络地址 broadcast = network | (~mask & 0xFFFFFFFF) # 按位或:主机位全置 1,得广播地址 print("网络地址:", int_to_ip(network)) # 201.222.5.152 print("广播地址:", int_to_ip(broadcast)) # 201.222.5.159逻辑说明:host & mask保留网络位、清零主机位,这是网络地址的定义,也是路由器转发时判断「目的地在不在本网段」的实际动作。~mask & 0xFFFFFFFF先把掩码取反得到主机位掩码(本题是0.0.0.7),再和网络地址按位或,把主机位全部填 1,得到广播地址。中间那个0xFFFFFFFF不能省,Python 的整数是任意精度,不截断会得到负数。
参数说明:mask换成255.255.255.240就是 /28,换成255.255.255.0就是 /24,改这一个值就能验算任意前缀。这段代码不依赖任何第三方库,适合在没有工具、只有一台装了 Python 的机器时应急。
4. 三种工具跑同一道题:HA_subnet10、子网计算工具 1.1、子网掩码计算器
4.1 三种输入口径,先认清再动手
实验报告要求用三款工具分别求解,难点不在软件本身,而在它们的输入口径并不统一。同一道题,有的工具让你填「要几个子网」,有的让你填「掩码或前缀」,有的让你填「每个子网几台主机」,填错口径得到的结果看着像对的,其实完全跑偏。
常见的有三种:
| 口径 | 输入项 | 本题该填 | 典型输出 |
|---|---|---|---|
| A 掩码驱动 | IP + 掩码/前缀 | 201.222.5.0 + 255.255.255.248 | 全部 32 个子网明细 |
| B 子网数驱动 | IP + 子网数 | 201.222.5.0 + 20 | 自动选掩码并列表 |
| C 主机数驱动 | IP + 每子网主机数 | 201.222.5.0 + 5 | 自动选掩码并列表 |
B 和 C 两种口径本质上是同一个计算过程的不同入口:B 从 2^n ≥ 子网数 解出 n,C 从 2^h - 2 ≥ 主机数 解出 h,然后用 n + h = 8 校验。如果工具只接受 B 口径、你却填了 5(想表达「每子网 5 台主机」),它会算出借 3 位、8 个子网、/27 的结果,掩码是 255.255.255.224——数字看起来很规整,但完全不满足 20 个子网的需求。这是这套实验里最容易翻车的一步。
4.2 逐个工具的操作路径与结果核对
HA_subnet10 这类工具通常是绿色小体积的 Windows 程序,界面元素以文本框和列表为主。典型操作顺序是:填入 IP 地址 → 选择地址类别或直接填掩码 → 填入子网数量或借位数 → 点击计算 → 下方列表输出每个子网的网络地址、首末主机、广播地址。要核对的字段有四个:子网掩码是否为 255.255.255.248、子网总数是否为 32、第一个子网是否是 201.222.5.0/29、第 20 个子网的广播地址是否是 201.222.5.159。
子网计算工具 1.1 的功能定位类似,差别往往在于它更倾向于让你直接输入子网位数而不是掩码。这时候填 5,而不是填 29,也不是填 248。如果不确定某个工具要的是位数还是掩码,最稳的办法是先拿一个已知答案的小例子试填一次,比如 /24 对应借 0 位、/26 对应借 2 位,试出来口径再回到正式题目。
子网掩码计算器一般是输入 IP 和前缀长度,输出网络地址、广播地址、可用主机范围和主机数量。它通常不做「按需选掩码」的推算,所以你得先把 /29 算出来再喂给它。它的价值在于结果字段拆得细,适合用来核对手工表里每一列的具体数字。
三款工具都跑完之后,把结果并排放:
| 核对项 | 手工推导 | HA_subnet10 | 子网计算工具 1.1 | 子网掩码计算器 |
|---|---|---|---|---|
| 子网掩码 | 255.255.255.248 | 应为同值 | 应为同值 | 应为同值 |
| 子网总数 | 32 | 应为 32 | 应为 32 | 不输出 |
| 第 1 个子网网络地址 | 201.222.5.0 | 应为同值 | 应为同值 | 应为同值 |
| 第 20 个子网网络地址 | 201.222.5.152 | 应为同值 | 应为同值 | 应为同值 |
| 第 20 个子网广播地址 | 201.222.5.159 | 应为同值 | 应为同值 | 应为同值 |
| 每子网可用主机 | 6 | 应为 6 | 应为 6 | 应为 6 |
出现一行对不上,先别改手工表,先怀疑工具的输入口径。这套实验的真正训练点就在这里:三款工具互为交叉验证,手工推导是第四方。四方一致,答案才算落定。
4.3 用 ipaddress 做第四种工具,可脚本化复现
Python 标准库里的ipaddress模块是最省事的「第四种工具」,不需要装任何软件,还能批量输出:
import ipaddress base = ipaddress.ip_network("201.222.5.0/24") # C 类网段,/24 subs = list(base.subnets(new_prefix=29)) # 借 5 位,切成 /29 print("子网总数:", len(subs)) # 32 # 抽查第 1、2、20、32 个子网,和手工表逐个对账 for idx in (0, 1, 19, 31): s = subs[idx] hosts = list(s.hosts()) # 自动排除网络地址和广播地址 print( f"第{idx + 1:>2}个 | 网络 {s.network_address} | " f"掩码 {s.netmask} | 广播 {s.broadcast_address} | " f"主机 {hosts[0]} ~ {hosts[-1]} | 可用 {len(hosts)} 台" )逻辑说明:subnets(new_prefix=29)不修改原网段,返回一个生成器,按第四字节从小到大依次产出 32 个 /29 子网,顺序和手工枚举完全一致,可以直接按索引对账。hosts()会自动剔除网络地址和广播地址,所以len(hosts)得到的 6 就是可用主机数,不用自己再减 2。
参数说明:new_prefix必须大于原前缀、小于等于 32,填 29 表示借 5 位;填 28 就是借 4 位、16 个子网,可以拿来做对照实验,验证「/28 不够用」这个结论。base用strict=True(默认值)时会拒绝带主机位的地址,比如201.222.5.3/24会直接抛异常,这个特性后面避坑章节会用到。
5. 避坑与排查:结果差一位、工具对不上、掩码选错的典型现场
5.1 掩码选型类的坑
现象一:算出 16 个子网,报告里写「满足 20 个子网需求」。原因:只看了「主机数够用」这一条约束,漏掉了子网数约束。n = 4 时 2^4 = 16 < 20,这一条就足以否决 /28。解决:两个不等式必须同时满足,先把子网数约束解出来定 n 的下界,再用主机数约束检查余量。本题 n 的下界是 5,主机数只是恰好也要求 h = 3,两者叠加才锁定 /29。养成习惯,每算出一个掩码,回填两个不等式各验一次,写在草稿上。
现象二:把 /30 当成「每子网 5 台主机」的答案。原因:只记住「/30 用于点对点链路,每网段 2 台主机」,看到需求 5 台觉得「差不多」。实际上 /30 只有 2 台可用主机,差得远。解决:可用主机数按 2^h - 2 算,h = 2 得 2,h = 3 得 6,5 台必须落进 h = 3 这一档。/30 的典型用途是路由器互联,一端一个地址,不用于接多台设备。
现象三:报告里写 30 个可用子网,工具显示 32 个。原因:老教材按 RFC 950 的规则扣掉全 0 和全 1 两个子网,得 2^n - 2 = 30;现代设备普遍支持ip subnet-zero,全 0 和全 1 子网可用,得 32。解决:这不是算错,是标准版本差异。做实验报告时按指导书的年代来写,同时把差异点注明;实际组网按 32 个规划。这道题里 30 和 32 都大于 20,不影响掩码结论,但结论栏要自洽,不能一半写 30 一半写 32。
5.2 工具口径与结果读取类的坑
现象四:同一份输入,HA_subnet10 算出 /27,手工算的是 /29。原因:把「每子网 5 台主机」填进了「子网数量」输入框。工具按 2^n ≥ 5 解出 n = 3,得到 8 个子网、/27。解决:认准输入框标签。要表达「每子网 5 台主机」,得找标注为主机数、每网段主机数、Hosts per subnet 一类字样的字段;找不到这类字段,说明工具只支持子网数驱动,那就自己先算出 20 对应的借位 5,填 5 或直接填掩码。
现象五:工具输出的第一个子网是 201.222.5.8,不是 .0。原因:部分老工具默认排除子网 0,或者把「第 1 个子网」理解为「第一个可用的非零子网」。解决:翻工具的设置项,找subnet zero、包含零子网一类开关;没有开关就手动在结果前面补一行 .0/29,并注明工具默认行为。写报告时编号要统一,手工表从 1 编到 32,工具结果也按同样口径重新编号,否则第 20 个子网会对到工具的第 21 行,越对越乱。
现象六:ipaddress抛出has host bits set。原因:ip_network("201.222.5.152/29")里 152 是网络地址,合法;但写成ip_network("201.222.5.153/29")就会报错,因为 153 带有主机位,不是合法网络地址。解决:确认要构造的是网段还是主机。网段用strict=True保证不写错;只是想从任意主机地址推导所属网段,用ip_interface()或显式传strict=False。这个报错看着烦,其实是免费的语法检查,能挡住一大批「网络地址写成主机地址」的低级错误。
6. 把手工表变成可复用的对账脚本
做完一遍实验,最值钱的产出其实不是那张 32 行的表,而是一个能随时重跑的对账脚本。下次题目换成 10.0.0.0/16 要切 100 个子网,改两个参数就能出结果,不用重新推一遍。
思路是把「手工表」写成断言,让脚本替你检查。断言通过,说明手工推导和程序计算互相印证;断言失败,报错会直接指出哪一行对不上,比人眼扫表快得多。
import ipaddress def build_table(cidr: str, new_prefix: int, checks: dict) -> list: """生成子网表,并用 checks 里的期望值做断言校验""" subs = list(ipaddress.ip_network(cidr).subnets(new_prefix=new_prefix)) rows = [] for i, s in enumerate(subs, 1): hosts = list(s.hosts()) rows.append({ "序号": i, "网络地址": str(s.network_address), "掩码": str(s.netmask), "广播地址": str(s.broadcast_address), "首个主机": str(hosts[0]), "末个主机": str(hosts[-1]), "可用主机数": len(hosts), }) for idx, expect in checks.items(): row = rows[idx - 1] for key, val in expect.items(): assert row[key] == val, f"第{idx}个子网 {key} 期望 {val},实际 {row[key]}" return rows # 把手工推导的关键结论写进断言,跑通即代表两套算法一致 checks = { 1: {"网络地址": "201.222.5.0", "广播地址": "201.222.5.7", "可用主机数": 6}, 20: {"网络地址": "201.222.5.152", "广播地址": "201.222.5.159", "可用主机数": 6}, 32: {"网络地址": "201.222.5.248", "广播地址": "201.222.5.255", "可用主机数": 6}, } rows = build_table("201.222.5.0/24", 29, checks) print(f"共 {len(rows)} 个子网,断言全部通过") for r in rows[:3] + rows[19:20] + rows[-1:]: print(r)这段代码有两个参数值得记住。new_prefix决定借位数,填 29 是本题答案,改成 28 会立刻让第 20 条的断言失败,报错信息会告诉你「第20个子网网络地址期望 201.222.5.152,实际 201.222.5.144」——这正好反向证明了 /28 不满足需求,比在报告里写一段文字论证有说服力。checks字典的键是子网序号,从 1 开始,和实验报告里的编号方式一致,写断言时不用换算索引。
另一个常用技巧是拿它做工具结果的复核。三款工具的输出没法直接喂给脚本,但你可以从每个工具的结果里各挑三五行关键数据手抄进checks,跑一遍脚本。全过,说明三款工具和手工推导四方一致;有报错,报错行就是那个工具填错口径的位置。
血泪经验是:别在工具之间来回切换着找答案。先把手推算死,写成断言,再让工具来对齐你,而不是你去迁就工具。从那以后我每次做地址规划,不管题目多简单,都强制走一遍「手工表 → 断言脚本 → 工具抽查」这三步,宁可多花五分钟,也不在报告交上去之后才发现掩码少借了一位。希望帮到你。
本文还有配套的精品资源,点击获取