9天:子网划分实战

第9天:子网划分实战

“子网划分就像把一栋大楼分成不同的房间。”

📚 今日目标

  • 理解子网掩码的概念和作用
  • 掌握CIDR表示法
  • 学会计算网络地址、广播地址
  • 能够进行子网划分
  • 编写子网计算器工具

🎯 为什么需要子网划分?

生活中的例子

没有子网划分:
一栋100层的大楼,所有人共用一个门牌号
→ 混乱、难以管理

有子网划分:
把大楼分成不同楼层,每层有自己的编号
→ 清晰、便于管理

网络也是一样:
- 节省IP地址
- 提高网络性能
- 增强安全性
- 便于管理

实际问题

问题:一个公司有500台电脑,给了一个C类地址192.168.1.0

C类地址只能容纳254台主机(2^8 - 2)

解决方案:
1. 申请多个C类地址(浪费、管理复杂)
2. 使用B类地址,然后划分子网(推荐)

📊 子网掩码

什么是子网掩码?

子网掩码(Subnet Mask)用于区分IP地址中的网络部分和主机部分。

IP地址:    192.168.1.100
子网掩码:  255.255.255.0

作用:确定哪些位是网络号,哪些位是主机号

子网掩码的格式

二进制表示:
网络部分:全是1
主机部分:全是0

例如:255.255.255.0
11111111.11111111.11111111.00000000
[    网络部分(24位)    ][主机部分(8位)]

常见的子网掩码

类别默认子网掩码二进制CIDR
A类255.0.0.011111111.00000000.00000000.00000000/8
B类255.255.0.011111111.11111111.00000000.00000000/16
C类255.255.255.011111111.11111111.11111111.00000000/24

🔢 CIDR表示法

什么是CIDR?

CIDR(Classless Inter-Domain Routing,无类域间路由)

/数字 表示子网掩码,数字表示网络位数。

传统表示:192.168.1.0  子网掩码:255.255.255.0
CIDR表示:192.168.1.0/24

/24 表示前24位是网络位,后8位是主机位

CIDR对照表

CIDR子网掩码可用主机数说明
/8255.0.0.016,777,214A类默认
/16255.255.0.065,534B类默认
/24255.255.255.0254C类默认
/25255.255.255.128126C类分2个子网
/26255.255.255.19262C类分4个子网
/27255.255.255.22430C类分8个子网
/28255.255.255.24014C类分16个子网
/29255.255.255.2486C类分32个子网
/30255.255.255.2522点对点链路

计算公式

网络位数:n
主机位数:32 - n

可用主机数 = 2^(主机位数) - 2

减2的原因:
- 网络地址(主机位全0)
- 广播地址(主机位全1)

例如:/24
主机位数 = 32 - 24 = 8
可用主机数 = 2^8 - 2 = 254

🧮 子网划分计算

基本概念

网络地址:主机位全为0 广播地址:主机位全为1 第一个可用IP:网络地址 + 1 最后一个可用IP:广播地址 - 1

计算步骤

例1:192.168.1.0/24

1. IP地址:192.168.1.0
2. 子网掩码:255.255.255.0 (/24)

计算:
网络地址:192.168.1.0
广播地址:192.168.1.255
第一个可用IP:192.168.1.1
最后一个可用IP:192.168.1.254
可用主机数:254

例2:192.168.1.0/25

1. IP地址:192.168.1.0
2. 子网掩码:255.255.255.128 (/25)

分析:
/25 表示前25位是网络位,后7位是主机位
255.255.255.128 = 11111111.11111111.11111111.10000000

子网1:
网络地址:192.168.1.0
广播地址:192.168.1.127
可用IP:192.168.1.1 - 192.168.1.126
可用主机数:126

子网2:
网络地址:192.168.1.128
广播地址:192.168.1.255
可用IP:192.168.1.129 - 192.168.1.254
可用主机数:126

快速计算技巧

1. 找到"变化的八位"
   255.255.255.128 → 最后一个八位是128

2. 计算块大小
   块大小 = 256 - 子网掩码最后非0的八位
   块大小 = 256 - 128 = 128

3. 列出子网
   第一个子网:0
   第二个子网:0 + 128 = 128
   第三个子网:128 + 128 = 256(超出范围,没有第三个)

所以子网是:
192.168.1.0/25
192.168.1.128/25

🔧 实战项目:子网计算器

让我们编写一个强大的子网计算器!

代码实现

# day09_subnet_calculator.py
# 功能:子网计算器

import math

class SubnetCalculator:
    """子网计算器"""

    def __init__(self):
        pass

    def cidr_to_mask(self, cidr):
        """
        将CIDR转换为子网掩码

        参数:
            cidr: CIDR值(如24)

        返回:
            子网掩码字符串(如 "255.255.255.0")
        """
        # 生成32位二进制,前cidr位是1,其余是0
        binary = '1' * cidr + '0' * (32 - cidr)

        # 分成4组,每组8位
        octets = [binary[i:i+8] for i in range(0, 32, 8)]

        # 转换为十进制
        mask = '.'.join([str(int(octet, 2)) for octet in octets])

        return mask

    def mask_to_cidr(self, mask):
        """
        将子网掩码转换为CIDR

        参数:
            mask: 子网掩码字符串(如 "255.255.255.0")

        返回:
            CIDR值
        """
        # 转换为二进制
        binary = ''.join([format(int(x), '08b') for x in mask.split('.')])

        # 计算1的个数
        return binary.count('1')

    def ip_to_int(self, ip):
        """将IP地址转换为整数"""
        parts = ip.split('.')
        return (int(parts[0]) << 24) + (int(parts[1]) << 16) + \
               (int(parts[2]) << 8) + int(parts[3])

    def int_to_ip(self, num):
        """将整数转换为IP地址"""
        return f"{(num >> 24) & 255}.{(num >> 16) & 255}." \
               f"{(num >> 8) & 255}.{num & 255}"

    def calculate_subnet(self, ip, cidr):
        """
        计算子网信息

        参数:
            ip: IP地址字符串
            cidr: CIDR值

        返回:
            包含所有子网信息的字典
        """
        # 转换为整数
        ip_int = self.ip_to_int(ip)

        # 计算子网掩码
        mask = self.cidr_to_mask(cidr)
        mask_int = self.ip_to_int(mask)

        # 计算网络地址(IP AND 掩码)
        network_int = ip_int & mask_int
        network = self.int_to_ip(network_int)

        # 计算广播地址(网络地址 OR 反码掩码)
        wildcard_int = ~mask_int & 0xFFFFFFFF  # 通配符掩码(反码)
        broadcast_int = network_int | wildcard_int
        broadcast = self.int_to_ip(broadcast_int)

        # 计算第一个和最后一个可用IP
        first_usable_int = network_int + 1
        last_usable_int = broadcast_int - 1

        first_usable = self.int_to_ip(first_usable_int)
        last_usable = self.int_to_ip(last_usable_int)

        # 计算主机数
        host_bits = 32 - cidr
        total_hosts = 2 ** host_bits
        usable_hosts = total_hosts - 2 if total_hosts > 2 else 0

        # 计算通配符掩码
        wildcard = self.int_to_ip(wildcard_int)

        result = {
            'ip': ip,
            'cidr': cidr,
            'mask': mask,
            'wildcard': wildcard,
            'network': network,
            'broadcast': broadcast,
            'first_usable': first_usable,
            'last_usable': last_usable,
            'total_hosts': total_hosts,
            'usable_hosts': usable_hosts
        }

        return result

    def split_subnet(self, ip, old_cidr, new_cidr):
        """
        将一个子网划分为多个更小的子网

        参数:
            ip: 原始网络地址
            old_cidr: 原始CIDR
            new_cidr: 新的CIDR(必须大于old_cidr)

        返回:
            子网列表
        """
        if new_cidr <= old_cidr:
            return None

        # 计算可以划分多少个子网
        num_subnets = 2 ** (new_cidr - old_cidr)

        # 计算每个子网的大小
        subnet_size = 2 ** (32 - new_cidr)

        # 获取起始网络地址
        start_int = self.ip_to_int(ip) & self.ip_to_int(self.cidr_to_mask(old_cidr))

        subnets = []
        for i in range(num_subnets):
            subnet_ip_int = start_int + (i * subnet_size)
            subnet_ip = self.int_to_ip(subnet_ip_int)
            subnets.append(f"{subnet_ip}/{new_cidr}")

        return subnets

    def print_subnet_info(self, info):
        """
        打印子网信息

        参数:
            info: calculate_subnet()返回的字典
        """
        print("=" * 70)
        print("子网信息".center(70))
        print("=" * 70)
        print(f"\n📍 IP地址:          {info['ip']}")
        print(f"🔢 CIDR:            /{info['cidr']}")
        print(f"🎭 子网掩码:        {info['mask']}")
        print(f"🃏 通配符掩码:      {info['wildcard']}")
        print(f"\n🌐 网络地址:        {info['network']}/{info['cidr']}")
        print(f"📡 广播地址:        {info['broadcast']}")
        print(f"\n🏁 第一个可用IP:    {info['first_usable']}")
        print(f"🏁 最后一个可用IP:  {info['last_usable']}")
        print(f"\n📊 总主机数:        {info['total_hosts']}")
        print(f"✅ 可用主机数:      {info['usable_hosts']}")
        print("=" * 70)

def main():
    """
    主函数
    """
    calc = SubnetCalculator()

    print("=" * 70)
    print("子网计算器".center(70))
    print("=" * 70)

    while True:
        print("\n请选择功能:")
        print("1. 计算子网信息")
        print("2. CIDR ↔ 子网掩码转换")
        print("3. 子网划分")
        print("4. 快速查询常用CIDR")
        print("0. 退出")

        choice = input("\n请输入选项: ").strip()

        if choice == '0':
            print("\n再见!")
            break

        elif choice == '1':
            ip = input("\n请输入IP地址: ").strip()
            cidr = input("请输入CIDR(如24): ").strip()

            try:
                cidr = int(cidr)
                if 0 <= cidr <= 32:
                    info = calc.calculate_subnet(ip, cidr)
                    calc.print_subnet_info(info)
                else:
                    print("❌ CIDR必须在0-32之间")
            except ValueError:
                print("❌ 请输入有效的数字")

        elif choice == '2':
            print("\n请选择转换方向:")
            print("1. CIDR → 子网掩码")
            print("2. 子网掩码 → CIDR")

            sub_choice = input("请输入选项: ").strip()

            if sub_choice == '1':
                cidr = input("\n请输入CIDR: ").strip()
                try:
                    cidr = int(cidr)
                    mask = calc.cidr_to_mask(cidr)
                    print(f"\n/{cidr} = {mask}")
                except ValueError:
                    print("❌ 请输入有效的数字")

            elif sub_choice == '2':
                mask = input("\n请输入子网掩码: ").strip()
                try:
                    cidr = calc.mask_to_cidr(mask)
                    print(f"\n{mask} = /{cidr}")
                except:
                    print("❌ 请输入有效的子网掩码")

        elif choice == '3':
            ip = input("\n请输入网络地址: ").strip()
            old_cidr = input("请输入原始CIDR: ").strip()
            new_cidr = input("请输入新的CIDR: ").strip()

            try:
                old_cidr = int(old_cidr)
                new_cidr = int(new_cidr)

                subnets = calc.split_subnet(ip, old_cidr, new_cidr)

                if subnets:
                    print(f"\n📊 将 {ip}/{old_cidr} 划分为 /{new_cidr} 子网:")
                    print(f"   共 {len(subnets)} 个子网\n")
                    for i, subnet in enumerate(subnets, 1):
                        print(f"   {i}. {subnet}")
                else:
                    print("❌ 新CIDR必须大于原CIDR")
            except ValueError:
                print("❌ 请输入有效的数字")

        elif choice == '4':
            print("\n常用CIDR速查表:")
            print(f"\n{'CIDR':<8} {'子网掩码':<18} {'可用主机数':<12} {'说明'}")
            print("-" * 60)

            common_cidrs = [
                (8, "A类默认"),
                (16, "B类默认"),
                (24, "C类默认"),
                (25, "C类分2个子网"),
                (26, "C类分4个子网"),
                (27, "C类分8个子网"),
                (28, "C类分16个子网"),
                (29, "小型子网"),
                (30, "点对点链路"),
            ]

            for cidr, desc in common_cidrs:
                mask = calc.cidr_to_mask(cidr)
                hosts = 2 ** (32 - cidr) - 2
                print(f"/{cidr:<7} {mask:<18} {hosts:<12} {desc}")

if __name__ == "__main__":
    main()

运行程序

python code/day09/day09_subnet_calculator.py

💡 实战案例

案例1:公司网络规划

需求:
公司有200台电脑,分布在4个部门
- 销售部:60台
- 技术部:80台
- 行政部:40台
- 财务部:20台

给定网络:192.168.0.0/24

方案:
1. 技术部:192.168.0.0/25(126台主机)
2. 销售部:192.168.0.128/26(62台主机)
3. 行政部:192.168.0.192/27(30台主机)
4. 财务部:192.168.0.224/27(30台主机)

案例2:家庭网络

需求:
家里有10台设备,使用C类私网

方案:
网络:192.168.1.0/24
- 可用IP:192.168.1.1 - 192.168.1.254
- 路由器:192.168.1.1
- 设备:192.168.1.100-109

🎓 知识小结

今天学习了:

  1. ✅ 子网掩码用于区分网络部分和主机部分
  2. ✅ CIDR是子网掩码的简写形式
  3. ✅ 可用主机数 = 2^主机位数 - 2
  4. ✅ 网络地址、广播地址的计算方法
  5. ✅ 子网划分的实际应用

重要公式

可用主机数 = 2^(32-CIDR) - 2
子网数量 = 2^(新CIDR - 旧CIDR)
块大小 = 256 - 子网掩码的变化八位

💪 练习题

练习1:基础计算

计算以下子网的信息:

  1. 192.168.10.0/24
  2. 172.16.0.0/16
  3. 10.0.0.0/8

练习2:子网划分

将192.168.1.0/24划分为:

  1. 2个相等的子网
  2. 4个相等的子网
  3. 8个相等的子网

练习3:实际应用

一个公司有以下需求:

  • 部门A:需要50台主机
  • 部门B:需要30台主机
  • 部门C:需要20台主机

给定192.168.0.0/24,如何划分?

练习4:进阶题目

如何判断两个IP是否在同一子网?

  • IP1: 192.168.1.100/25
  • IP2: 192.168.1.150/25

💡 今日金句:子网划分是网络规划的基本功!

👉 上一天:IP地址详解 | 返回目录 | 下一天:MAC地址和ARP