2天:网络的分类和拓扑结构

第2天:网络的分类和拓扑结构

“网络就像城市的交通系统,有不同的规模和不同的连接方式。”

📚 今日目标

  • 理解网络的分类(LAN、WAN、MAN)
  • 掌握网络拓扑结构的类型
  • 编写程序:扫描局域网设备

🌐 网络的分类

按地理范围分类

1. 局域网(LAN - Local Area Network)

定义:覆盖范围较小的网络,通常在一个建筑物或校园内。

生活中的例子

  • 你家里的WiFi网络
  • 公司办公室的网络
  • 网吧的网络
  • 学校机房的网络

特点

  • 📏 范围:几米到几公里
  • 🚀 速度:很快(100Mbps - 10Gbps)
  • 💰 成本:低
  • 👥 归属:个人或单位所有
类比理解:
局域网 = 你家的内部电话系统
只能在家里几个房间之间通话

2. 城域网(MAN - Metropolitan Area Network)

定义:覆盖一个城市范围的网络。

生活中的例子

  • 城市的有线电视网络
  • 城市公共WiFi网络
  • 城市监控网络

特点

  • 📏 范围:几十公里
  • 🚀 速度:较快
  • 💰 成本:中等
  • 👥 归属:通常是运营商或政府
类比理解:
城域网 = 城市的公交系统
连接城市内的不同区域

3. 广域网(WAN - Wide Area Network)

定义:覆盖很大地理范围的网络,可以跨越国家和大洲。

生活中的例子

  • 互联网(Internet)
  • 跨国公司的专用网络
  • 电信运营商的骨干网

特点

  • 📏 范围:几百到几万公里
  • 🚀 速度:相对较慢
  • 💰 成本:高
  • 👥 归属:运营商或大型组织
类比理解:
广域网 = 国际航空网络
连接世界各地的城市

对比总结

类型覆盖范围传输速度延迟例子
LAN10m - 1km最快最低家庭WiFi
MAN10km - 100km较快较低城市网络
WAN100km+较慢较高互联网

🔷 网络拓扑结构

拓扑结构就是网络中各个设备的连接方式和布局形状。

1. 总线型拓扑(Bus Topology)

设备A --- 设备B --- 设备C --- 设备D
         |                      |
       (总线)                (总线)

特点

  • ✅ 优点:布线简单,成本低
  • ❌ 缺点:总线断了,整个网络瘫痪
  • 📝 应用:早期以太网

类比:公交线路,所有站点都在一条线上

2. 星型拓扑(Star Topology)

        设备B
          |
设备A -- 交换机 -- 设备C
          |
        设备D

特点

  • ✅ 优点:一个设备故障不影响其他设备
  • ✅ 管理方便,易于排错
  • ❌ 缺点:中心设备(交换机)故障,整个网络瘫痪
  • 📝 应用:现代最常用的拓扑结构

类比:太阳系,所有行星围绕太阳转

3. 环型拓扑(Ring Topology)

设备A --- 设备B
  |          |
设备D --- 设备C

特点

  • ✅ 优点:数据传输路径确定
  • ❌ 缺点:一个设备故障影响整个网络
  • 📝 应用:令牌环网络(已较少使用)

类比:接力赛跑,每个人传递给下一个人

4. 网状型拓扑(Mesh Topology)

设备A --- 设备B
 | \    / |
 |  \ /   |
 |  / \   |
 | /    \ |
设备D --- 设备C

特点

  • ✅ 优点:可靠性极高,有多条路径
  • ❌ 缺点:布线复杂,成本高
  • 📝 应用:军事网络、互联网骨干

类比:地铁网络,有多条线路可选

5. 树型拓扑(Tree Topology)

        根交换机
        /      \
     交换机A   交换机B
     /   \      /   \
   设备1 设备2 设备3 设备4

特点

  • ✅ 优点:易于扩展,层次清晰
  • ❌ 缺点:根节点故障影响所有下级
  • 📝 应用:企业网络、校园网

类比:公司组织架构

🔧 实战项目:局域网设备扫描器

让我们编写一个程序,扫描你所在局域网内的所有设备!

代码实现

# day02_lan_scanner.py
# 功能:扫描局域网内的活跃设备

import socket
import ipaddress
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed

def get_local_ip_and_subnet():
    """
    获取本机IP地址和所在的子网

    返回:
        local_ip: 本机IP地址字符串
        subnet: 子网字符串(如 "192.168.1.0/24")
    """
    try:
        # 创建socket连接到外部地址,获取本机IP
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.connect(("8.8.8.8", 80))
        local_ip = sock.getsockname()[0]
        sock.close()

        # 从IP地址推断子网(假设是/24子网)
        # 例如:192.168.1.100 -> 192.168.1.0/24
        ip_parts = local_ip.split('.')
        subnet = f"{ip_parts[0]}.{ip_parts[1]}.{ip_parts[2]}.0/24"

        return local_ip, subnet

    except Exception as e:
        print(f"获取本机IP失败:{e}")
        return None, None

def check_host(ip, timeout=0.5):
    """
    检查指定IP的主机是否在线

    参数:
        ip: 要检查的IP地址
        timeout: 超时时间(秒)

    返回:
        如果主机在线,返回(ip, hostname)
        如果主机不在线,返回None

    工作原理:
        尝试连接到目标IP的常用端口(80端口)
        如果能连接,说明主机在线
    """
    try:
        # 尝试连接到80端口(HTTP端口)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)

        # 尝试连接
        result = sock.connect_ex((str(ip), 80))

        if result == 0:
            # 连接成功,尝试获取主机名
            try:
                hostname = socket.gethostbyaddr(str(ip))[0]
            except:
                hostname = "未知主机名"

            sock.close()
            return (str(ip), hostname)
        else:
            sock.close()
            return None

    except:
        return None

def ping_check(ip, timeout=0.5):
    """
    使用更简单的方法检测主机是否在线
    尝试多个常用端口
    """
    common_ports = [80, 443, 22, 445, 139]  # HTTP, HTTPS, SSH, SMB

    for port in common_ports:
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(timeout)
            result = sock.connect_ex((str(ip), port))
            sock.close()

            if result == 0:
                # 尝试获取主机名
                try:
                    hostname = socket.gethostbyaddr(str(ip))[0]
                except:
                    hostname = "未知主机名"

                return (str(ip), hostname, port)

        except:
            continue

    return None

def scan_network(subnet, max_workers=50):
    """
    扫描整个子网

    参数:
        subnet: 子网地址(如 "192.168.1.0/24")
        max_workers: 最大线程数

    返回:
        活跃主机列表
    """
    # 解析子网,获取所有IP地址
    network = ipaddress.ip_network(subnet, strict=False)
    total_hosts = network.num_addresses - 2  # 减去网络地址和广播地址

    print(f"🔍 开始扫描子网: {subnet}")
    print(f"📊 总共需要扫描 {total_hosts} 个IP地址")
    print(f"⏳ 请稍候...\n")

    active_hosts = []
    scanned = 0

    # 使用线程池并发扫描
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        # 提交所有扫描任务
        future_to_ip = {
            executor.submit(ping_check, ip): ip
            for ip in network.hosts()  # 排除网络地址和广播地址
        }

        # 处理完成的任务
        for future in as_completed(future_to_ip):
            scanned += 1
            result = future.result()

            if result:
                ip, hostname, port = result
                active_hosts.append((ip, hostname, port))
                print(f"✅ 发现设备: {ip:15} | {hostname:30} | 端口: {port}")

            # 显示进度
            if scanned % 10 == 0:
                progress = (scanned / total_hosts) * 100
                print(f"   进度: {progress:.1f}% ({scanned}/{total_hosts})", end='\r')

    return active_hosts

def display_topology(active_hosts, local_ip):
    """
    显示网络拓扑结构(简化版)
    """
    print("\n" + "=" * 70)
    print("网络拓扑结构(星型拓扑)".center(70))
    print("=" * 70)
    print()
    print("                      [路由器/交换机]")
    print("                             |")
    print("          " + "-" * 40)

    for ip, hostname, port in active_hosts:
        marker = " (本机)" if ip == local_ip else ""
        print(f"          |-- [{ip}] {hostname}{marker}")

    print()
    print("=" * 70)

def main():
    """
    主函数
    """
    print("=" * 70)
    print("局域网设备扫描器".center(70))
    print("=" * 70)
    print()

    # 获取本机IP和子网
    local_ip, subnet = get_local_ip_and_subnet()

    if not local_ip:
        print("❌ 无法获取本机IP地址,请检查网络连接!")
        return

    print(f"📍 本机IP: {local_ip}")
    print(f"🌐 所在子网: {subnet}")
    print()

    # 扫描网络
    active_hosts = scan_network(subnet)

    print("\n" + "=" * 70)
    print(f"✨ 扫描完成!共发现 {len(active_hosts)} 台活跃设备")
    print("=" * 70)

    # 显示详细信息
    if active_hosts:
        print("\n📋 活跃设备列表:")
        print(f"{'IP地址':<15} | {'主机名':<30} | {'开放端口'}")
        print("-" * 70)

        for ip, hostname, port in active_hosts:
            marker = " ⭐" if ip == local_ip else ""
            print(f"{ip:<15} | {hostname:<30} | {port}{marker}")

        # 显示拓扑结构
        display_topology(active_hosts, local_ip)

        # 分析网络类型
        print("\n💡 网络分析:")
        print(f"   - 这是一个局域网(LAN)")
        print(f"   - 使用星型拓扑结构")
        print(f"   - 共有 {len(active_hosts)} 台设备连接到同一个交换机/路由器")

    else:
        print("\n⚠️  未发现其他活跃设备")

if __name__ == "__main__":
    main()

运行程序

cd code/day02
python day02_lan_scanner.py

预期输出

======================================================================
                         局域网设备扫描器
======================================================================

📍 本机IP: 192.168.1.100
🌐 所在子网: 192.168.1.0/24

🔍 开始扫描子网: 192.168.1.0/24
📊 总共需要扫描 254 个IP地址
⏳ 请稍候...

✅ 发现设备: 192.168.1.1     | router.home                     | 端口: 80
✅ 发现设备: 192.168.1.100   | linzhibin-MacBook              | 端口: 80
✅ 发现设备: 192.168.1.105   | xiaomi-phone                   | 端口: 443

======================================================================
✨ 扫描完成!共发现 3 台活跃设备
======================================================================

📋 活跃设备列表:
IP地址           | 主机名                          | 开放端口
----------------------------------------------------------------------
192.168.1.1     | router.home                    | 80
192.168.1.100   | linzhibin-MacBook              | 80 ⭐
192.168.1.105   | xiaomi-phone                   | 443

======================================================================
                    网络拓扑结构(星型拓扑)
======================================================================

                      [路由器/交换机]
                             |
          ----------------------------------------
          |-- [192.168.1.1] router.home
          |-- [192.168.1.100] linzhibin-MacBook (本机)
          |-- [192.168.1.105] xiaomi-phone

======================================================================

💡 网络分析:
   - 这是一个局域网(LAN)
   - 使用星型拓扑结构
   - 共有 3 台设备连接到同一个交换机/路由器

🔍 代码详解

1. ipaddress模块

Python的ipaddress模块用于处理IP地址和网络:

import ipaddress

# 创建网络对象
network = ipaddress.ip_network("192.168.1.0/24")

# 获取网络中的所有主机IP
for ip in network.hosts():
    print(ip)  # 192.168.1.1, 192.168.1.2, ..., 192.168.1.254

2. 子网掩码 /24 是什么意思?

192.168.1.0/24 的含义:

/24 表示子网掩码有24个1:
11111111.11111111.11111111.00000000
即:255.255.255.0

可用IP范围:
192.168.1.1 到 192.168.1.254(共254个)
192.168.1.0 是网络地址
192.168.1.255 是广播地址

3. ThreadPoolExecutor 并发扫描

from concurrent.futures import ThreadPoolExecutor

# 创建线程池,最多50个线程同时工作
with ThreadPoolExecutor(max_workers=50) as executor:
    # 提交任务
    futures = [executor.submit(scan_ip, ip) for ip in ip_list]

    # 等待完成
    for future in as_completed(futures):
        result = future.result()

为什么要用多线程?

  • 单线程扫描254个IP需要很长时间
  • 多线程可以同时扫描多个IP,大大提高效率
  • 50个线程可以让扫描速度提升几十倍

4. connect_ex方法

result = sock.connect_ex((ip, port))

# 返回值:
# 0 = 连接成功
# 其他 = 连接失败(错误码)

这比普通的connect()方法更好,因为失败时不会抛出异常。

🎓 知识小结

今天学到了什么?

  1. ✅ 网络按范围分为LAN、MAN、WAN
  2. ✅ 家庭和办公室网络是局域网(LAN)
  3. ✅ 网络拓扑结构有5种:总线、星型、环型、网状、树型
  4. ✅ 现代网络最常用星型拓扑结构
  5. ✅ 子网的概念和表示方法
  6. ✅ 如何扫描局域网内的设备

重要概念

概念解释例子
局域网小范围的网络家庭WiFi
星型拓扑所有设备连接到中心节点所有电脑连接到路由器
子网一个网络的子集192.168.1.0/24
主机网络中的设备你的电脑、手机

💪 练习题

练习1:识别拓扑类型

说出以下场景使用的是什么拓扑结构:

  1. 所有教室的电脑都连接到机房的交换机
  2. 地铁13号线各个站点的连接
  3. 互联网骨干网的连接方式

练习2:修改扫描器

修改程序,让它可以:

  1. 扫描自定义的子网(不是默认的/24)
  2. 显示每个设备的响应时间
  3. 保存扫描结果到文件

练习3:计算题

一个192.168.1.0/24的网络:

  1. 子网掩码是多少?
  2. 第一个可用IP是多少?
  3. 最后一个可用IP是多少?
  4. 总共有多少个可用IP?

练习4:绘制拓扑图

绘制你家里或公司的网络拓扑结构图,标注:

  • 所有设备(电脑、手机、打印机等)
  • 路由器/交换机
  • 连接方式(有线/无线)

📚 扩展阅读

为什么星型拓扑最流行?

历史原因

  • 早期使用总线型拓扑(10BASE-2同轴电缆)
  • 问题:一根线断了,所有设备都不能用
  • 星型拓扑解决了这个问题

现代优势

  • 便于管理:可以在交换机上管理每个端口
  • 易于排错:某个设备故障不影响其他设备
  • 易于扩展:只需在交换机上增加端口
  • 性能好:交换机可以智能转发数据

家庭网络的实际拓扑

互联网
  |
光猫
  |
路由器(WiFi)
  |
  |---- 电脑(有线)
  |---- 手机(无线)
  |---- 平板(无线)
  |---- 智能电视(有线)
  |---- 智能音箱(无线)

这是一个典型的星型拓扑

企业网络的拓扑

            核心交换机(根)
              /      \
         交换机A    交换机B
         /   \       /   \
       电脑1 电脑2 电脑3 电脑4

这是一个树型拓扑(也叫分层星型拓扑)!

🎯 明天预告

第3天:OSI七层模型

我们将学习:

  • 什么是OSI七层模型?
  • 每一层做什么?
  • 为什么要分层?
  • 编写程序分析各层的作用

💡 今日金句:网络拓扑就像城市规划,不同的结构有不同的优缺点!

👉 上一天:认识计算机网络 | 返回目录 | 下一天:OSI七层模型