大一網際網路應用|Python UDP 分組網路實作:1 位組長收集 5 位組員的 IP、MAC、學號與姓名
在「網際網路應用」課程中,我們會學到 IP Address、MAC Address、Port、Socket、TCP、UDP、Client 與 Server 等重要觀念。 如果只記住名詞定義,很難真正理解電腦之間到底如何交換資料。
因此這次我們直接進行一個學生分組網路實驗。 每組由一位學生擔任組長(Group Leader), 組長的電腦同時擔任 UDP Server; 另外 5 位學生擔任組員(Node)。
每位組員執行 Python 程式後,只要輸入自己的學號與姓名, 程式會取得該電腦的 IP 與 MAC Address, 再透過 UDP 傳送到組長電腦。
如何讓一組學生自己建立一個小型區域網路, 由「組長 Server」收集 5 位「組員 Node」的網路與身分資料?
一、學習目標
- 理解 Client / Server 網路架構。
- 了解 IP Address、MAC Address 與 Port 的基本角色。
- 了解 TCP 與 UDP 的基本差異。
- 使用 Python Socket 建立 UDP 通訊。
- 使用 JSON 傳送結構化資料。
- 觀察 UDP 封包的實際來源 IP。
- 讓學生自己完成一個小型區域網路。
- 建立「組長 Server + 5 個組員 Node」的分組合作模式。
二、分組方式
每組共有 6 位學生:
| 角色 | 人數 | 程式 | 主要任務 |
|---|---|---|---|
| 組長 | 1 | udp_leader.py | UDP Server |
| 組員 | 5 | udp_node.py | UDP Node |
三、網路架構
組員1 Node ─┐
組員2 Node ─┤
組員3 Node ─┤
組員4 Node ─┤── UDP ──→ 組長 Server
組員5 Node ─┘ Port 5005
│
↓
建立本組節點資料表
例如組長電腦的 IP 是:
192.168.1.100
其他 5 位組員可能是:
組員1:192.168.1.101 組員2:192.168.1.102 組員3:192.168.1.103 組員4:192.168.1.104 組員5:192.168.1.105
實際 IP 由教室的 DHCP 或網路設定決定, 不一定與範例相同。
四、誰是 Server?誰是 Client?
這個實驗中,老師不再擔任 Server。
組員:擔任 UDP Client / Node,將自己的資料傳送給組長。
因此一個小組本身就是一個簡單的 Client / Server 網路:
組員 Node
│
組員 Node
│
組員 Node
│
組員 Node
│
組員 Node
│
↓
組長 Server
這也說明一個重要觀念: Server 不一定是一台大型主機。 只要一支程式正在等待並提供某種網路服務, 一般筆記型電腦也可以暫時扮演 Server。
五、TCP 與 UDP
TCP 與 UDP 都是常見的傳輸層協定。 本次實驗選擇 UDP。
| 比較 | TCP | UDP |
|---|---|---|
| 建立連線 | 需要 | 不需要 |
| 可靠傳輸機制 | 有 | 本身不保證 |
| 順序控制 | 有 | 本身不保證 |
| 協定負擔 | 較多 | 較少 |
可以先把 TCP 想成「打電話」, UDP 則像「直接寄出一張明信片」。
但我們可以在應用程式中自行加入確認機制。 所以本實驗設計成:
組員 │ │ UDP:我的資料 ↓ 組長 │ │ UDP:已收到 ↓ 組員
六、每位組員要傳什麼?
每位組員傳送四項資料:
- 學號 student_id
- 姓名 name
- IP Address
- MAC Address
例如:
{
"student_id": "411001001",
"name": "王小明",
"ip": "192.168.1.101",
"mac": "34:12:98:AA:01:10"
}
這就是 JSON 格式。
整個資料處理流程為:
Python Dictionary
↓
JSON
↓
UTF-8
↓
Bytes
↓
UDP
七、組長端完整程式
組長將程式儲存為:
udp_leader.py
import socket
import json
SERVER_IP = "0.0.0.0"
SERVER_PORT = 5005
sock = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM
)
sock.bind(
(SERVER_IP, SERVER_PORT)
)
students = {}
print("=" * 60)
print("UDP 小組節點資料收集系統")
print("本電腦角色:組長 Server")
print(f"等待 UDP Port {SERVER_PORT}...")
print("=" * 60)
while len(students) < 5:
data, address = sock.recvfrom(4096)
try:
student = json.loads(
data.decode("utf-8")
)
student_id = student["student_id"]
name = student["name"]
ip = student["ip"]
mac = student["mac"]
students[student_id] = {
"name": name,
"ip": ip,
"mac": mac,
"source_ip": address[0]
}
print()
print(f"目前收到 {len(students)} / 5 位組員")
print("-" * 50)
print(f"學號:{student_id}")
print(f"姓名:{name}")
print(f"組員回報 IP:{ip}")
print(f"實際來源 IP:{address[0]}")
print(f"MAC:{mac}")
print(f"來源 Port:{address[1]}")
print("-" * 50)
message = (
f"組長已收到 "
f"{student_id} {name} 的資料"
)
sock.sendto(
message.encode("utf-8"),
address
)
except Exception as e:
print("資料格式錯誤:", e)
print()
print("=" * 90)
print("本組 5 位組員資料收集完成")
print("=" * 90)
print(
f"{'學號':<15}"
f"{'姓名':<12}"
f"{'回報IP':<18}"
f"{'來源IP':<18}"
f"{'MAC'}"
)
print("-" * 90)
for student_id, info in students.items():
print(
f"{student_id:<15}"
f"{info['name']:<12}"
f"{info['ip']:<18}"
f"{info['source_ip']:<18}"
f"{info['mac']}"
)
sock.close()
八、5 位組員使用的完整程式
5 位組員全部使用同一支程式:
udp_node.py
import socket
import uuid
import json
# =========================================
# 修改成「組長電腦」的 IP
# =========================================
LEADER_IP = "192.168.1.100"
SERVER_PORT = 5005
# =========================================
# 取得本機 IP
# =========================================
def get_ip():
s = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM
)
try:
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
except:
ip = "127.0.0.1"
finally:
s.close()
return ip
# =========================================
# 取得本機 MAC Address
# =========================================
def get_mac():
mac = uuid.getnode()
return ":".join(
f"{(mac >> i) & 0xff:02X}"
for i in range(40, -1, -8)
)
# =========================================
# 主程式
# =========================================
print("=" * 50)
print("UDP 小組節點資料傳送程式")
print("本電腦角色:組員 Node")
print("=" * 50)
student_id = input("請輸入學號:")
name = input("請輸入姓名:")
ip = get_ip()
mac = get_mac()
student = {
"student_id": student_id,
"name": name,
"ip": ip,
"mac": mac
}
print()
print("準備傳送資料")
print("-" * 40)
print("學號:", student_id)
print("姓名:", name)
print("IP:", ip)
print("MAC:", mac)
print("-" * 40)
print("組長 IP:", LEADER_IP)
# 建立 UDP Socket
sock = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM
)
# Dictionary → JSON → Bytes
data = json.dumps(
student,
ensure_ascii=False
).encode("utf-8")
# 傳送給組長
sock.sendto(
data,
(LEADER_IP, SERVER_PORT)
)
print()
print("資料已透過 UDP 傳送給組長!")
# 等待組長回覆
sock.settimeout(5)
try:
reply, address = sock.recvfrom(4096)
print(
"組長回覆:",
reply.decode("utf-8")
)
except socket.timeout:
print("5 秒內沒有收到組長回覆")
sock.close()
九、實驗操作流程
本實驗最重要的是執行順序。
↓
② 選出一位組長
↓
③ 組長查詢自己的 IP
↓
④ 組長將 IP 告訴 5 位組員
↓
⑤ 組長先執行 udp_leader.py
↓
⑥ 5 位組員設定 LEADER_IP
↓
⑦ 組員執行 udp_node.py
↓
⑧ 輸入學號與姓名
↓
⑨ UDP 傳送資料
↓
⑩ 組長完成本組節點資料表
十、組長如何查自己的 IP?
Windows 可以開啟命令提示字元:
ipconfig
找到目前使用中的網路介面,例如:
IPv4 Address . . . . . . . . . : 192.168.1.100
組長就告訴其他 5 位組員:
5 位組員修改:
LEADER_IP = "192.168.1.100"
十一、組長先啟動 Server
組長執行:
python udp_leader.py
畫面:
============================================================ UDP 小組節點資料收集系統 本電腦角色:組長 Server 等待 UDP Port 5005... ============================================================
這代表組長電腦正在等待其他組員送資料到 UDP Port 5005。
十二、組員開始傳送
組員執行:
python udp_node.py
例如:
請輸入學號:411001001 請輸入姓名:王小明 準備傳送資料 ---------------------------------------- 學號:411001001 姓名:王小明 IP:192.168.1.101 MAC:34:12:98:AA:01:10 ---------------------------------------- 組長 IP:192.168.1.100 資料已透過 UDP 傳送給組長! 組長回覆: 組長已收到 411001001 王小明 的資料
十三、組長會看到什麼?
第一位組員傳送後:
目前收到 1 / 5 位組員 -------------------------------------------------- 學號:411001001 姓名:王小明 組員回報 IP: 192.168.1.101 實際來源 IP: 192.168.1.101 MAC: 34:12:98:AA:01:10 來源 Port: 52341
這裡要特別觀察:
與
組長 Server 從 UDP 封包看到的來源 IP
兩者是不是相同?
十四、recvfrom() 告訴組長什麼?
組長程式中最重要的一行之一:
data, address = sock.recvfrom(4096)
它會得到:
data │ └── 組員傳送的 JSON 資料 address │ ├── 來源 IP └── 來源 Port
例如:
('192.168.1.101', 52341)
因此:
address[0]
就是組長實際看到的來源 IP。
十五、MAC 為什麼不是組長直接查到的?
本實驗中的 MAC 是:
組員電腦 ↓ uuid.getnode() ↓ 取得本機 MAC ↓ 放入 Python Dictionary ↓ 轉成 JSON ↓ UDP ↓ 組長 Server
因此:
它不是組長使用
recvfrom() 直接從遠端 UDP 封包取得的 MAC Address。
十六、5 位組員完成後
當組長收到 5 個不同學號後:
========================================================================================== 本組 5 位組員資料收集完成 ========================================================================================== 學號 姓名 回報IP 來源IP MAC ------------------------------------------------------------------------------------------ 411001001 王小明 192.168.1.101 192.168.1.101 34:12:98:AA:01:10 411001002 李小華 192.168.1.102 192.168.1.102 50:EB:F6:22:18:21 411001003 陳大文 192.168.1.103 192.168.1.103 10:62:E5:31:21:33 411001004 林小美 192.168.1.104 192.168.1.104 A4:BB:6D:11:23:44 411001005 張志明 192.168.1.105 192.168.1.105 D8:43:AE:12:35:55
到這裡,一個由學生自行建立的 「1 Server + 5 Nodes」小型網路 就完成了。
十七、從輸入姓名到組長收到資料
把整個網路資料流串起來:
↓
Python 取得 IP、MAC
↓
建立 Dictionary
↓
轉成 JSON
↓
UTF-8 編碼
↓
Socket
↓
UDP
↓
IP Network
↓
組長 IP
↓
UDP Port 5005
↓
recvfrom()
↓
JSON Decode
↓
加入本組節點資料表
↓
組長回覆「已收到」
十八、實驗失敗時如何檢查?
- 組長與組員是否位於可以互通的網路環境。
- 組長 IP 是否查詢正確。
- 5 位組員的
LEADER_IP是否設定正確。 - 組長是否先啟動
udp_leader.py。 - UDP Port 5005 是否受到防火牆限制。
- Python 是否取得 Windows 防火牆的網路存取權限。
- 校園 Wi-Fi 是否啟用 Client Isolation / AP Isolation。
如果校園 Wi-Fi 基於資訊安全限制學生裝置互相連線, 可依學校網路政策使用教學實驗用 AP 建立獨立區域網路。
十九、課堂思考題
- 為什麼組長要先啟動程式?
- 組長在這個實驗中扮演 Server 還是 Client?
- 5 位組員為什麼都必須知道組長 IP?
- Port 5005 的作用是什麼?
AF_INET表示什麼?SOCK_DGRAM與 UDP 有什麼關係?- IP Address 和 MAC Address 的角色有什麼不同?
- 為什麼組員要把資料轉成 JSON?
recvfrom()可以取得哪些資訊?- 為什麼組長可以知道封包的來源 IP,卻不能用同樣方式取得跨網段的遠端 MAC?
- UDP 封包如果遺失,這支程式會自動重傳嗎?
- 如果組長換人,程式的網路架構需要修改哪些地方?
二十、進階實驗:組長也加入節點
目前架構是:
1 位組長 Server + 5 位組員 Node = 6 位學生
下一階段可以進一步讓組長不只是 Server, 同時也是一個 Node:
組長
Server + Node
↑ ↓
┌──────┼──────┐
↓ ↓ ↓
組員1 組員2 組員3
↑ ↑ ↑
└── 組員4、組員5 ──┘
再進一步加入:
- UDP Broadcast:自動尋找組長。
- UDP Unicast:指定某位組員傳送訊息。
- 節點上線通知。
- 節點離線通知。
- 簡易群組聊天室。
二十一、結語:每一組就是一個小型網路實驗室
這次實驗最大的改變,是老師不再擔任 Server。
每組由學生自己選出一位組長, 組長的筆記型電腦就是 Server; 其他同學的電腦就是 Node。
↓
選出 1 位組長
↓
組長建立 UDP Server
↓
5 位組員建立 UDP Node
↓
Socket + IP + Port
↓
JSON + UDP
↓
完成本組節點資料表
透過這個實驗,同學不只是背誦 IP、MAC、Port、Socket、UDP、Client 與 Server, 而是親手讓這些技術真正運作一次。
更重要的是,每一組學生都自己建立了一個 「1 Server + 5 Nodes」的小型區域網路。 這可以作為後續學習 UDP Broadcast、Peer-to-Peer、IoT、即時通訊與網路服務 的重要基礎。
沒有留言:
張貼留言