Mininet使用笔记(三)UDP通讯
一、准备
# 查看拓扑
mininet> dump
<Host h1: h1-eth0:10.0.0.1 pid=2390682>
<Host h2: h2-eth0:10.0.0.2 pid=2390684>
<OVSBridge s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=2390689>
UDP 服务端(udp_server.py)
import socket
HOST = "0.0.0.0"
PORT = 8888
srv_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
srv_sock.bind((HOST, PORT))
print(f"UDP Server listen on {HOST}:{PORT}")
while True:
data, addr = srv_sock.recvfrom(1024)
print(f"Recv from {addr}: {data.decode('utf-8')}")
srv_sock.sendto(b"Server ACK:" + data, addr)
UDP 客户端(udp_client.py)
import socket
SERVER_IP = "10.0.0.1"
SERVER_PORT = 8888
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
msg = b"Hello UDP Test"
cli_sock.sendto(msg, (SERVER_IP, SERVER_PORT))
resp, addr = cli_sock.recvfrom(1024)
print(f"Recv reply: {resp.decode()}")
cli_sock.close()
二、正常 UDP 通讯抓包
# 终端1:h1 运行 UDP SERVER
mininet> h1 python3 udp_server.py
UDP Server listen on 0.0.0.0:8888
Recv from ('10.0.0.2', 42837): Hello UDP Test
# 终端2:h2 运行 UDP CLIENT
root@null:/home/null# sudo mnexec -a 2390684 python3 udp_client.py
Recv reply: Server ACK:Hello UDP Test
# 终端3:h2 抓包 UDP 通讯
root@null:/home/null# sudo mnexec -a 2390684 tcpdump -l -i h2-eth0 udp port 8888
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on h2-eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
13:21:05.673793 IP 10.0.0.2.39782 > 10.0.0.1.8888: UDP, length 14
13:21:05.674060 IP 10.0.0.1.8888 > 10.0.0.2.39782: UDP, length 25
三、模拟 UDP 客户端数据丢包
在客户端端 h2 添加 INPUT 过滤规则
mininet> h2 iptables -A INPUT -s 10.0.0.1 -p udp --sport 8888 -j DROP
# 终端1:h1 运行 UDP SERVER
mininet> h1 python3 udp_server.py
UDP Server listen on 0.0.0.0:8888
Recv from ('10.0.0.2', 42837): Hello UDP Test
# 终端2:h2 运行 UDP CLIENT
root@null:/home/null# sudo mnexec -a 2390684 python3 udp_client.py
# [无返回ACK数据]
# 终端3:h2 抓包 UDP 8888 端口报文
root@null:/home/null# sudo mnexec -a 2390684 tcpdump -l -i h2-eth0 udp port 8888
[sudo] password for null:
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on h2-eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:23:19.959552 IP 10.0.0.2.42837 > 10.0.0.1.8888: UDP, length 14
14:23:19.959891 IP 10.0.0.1.8888 > 10.0.0.2.42837: UDP, length 25
四、总结
从抓包结果就可以看出,UDP 通讯很简单:没有握手、挥手报文,没有重试,也就是说 UDP 没有重传、超时、指数退避机制,发送即忘 (Send‑and‑pray)。如果想实现「超时 + 指数退避重试」,只能在应用层代码里实现。示例:
import socket
import time
SERVER_IP = "10.0.0.1"
SERVER_PORT = 8888
cli_sock =_INET, socket.SOCK_INET, socket.SOCK_DGRAM)
# 设置超时时间
base_timeout = 1
max_retry = 4
retry_count = 0
msg = b"Hello UDP Test"
while retry_count <= max_retry:
cli_sock.sendto(msg, (SERVER_IP, SERVER_PORT))
print(f"Send msg: {retry_count+1} times")
# 指数退避:1s -> 2s -> 4s -> 8s
timeout = base_timeout * (2 ** retry_count)
cli_sock.settimeout(timeout)
try:
resp, addr = cli_sock.recvfrom(1024)
print(f"Recv reply: {resp.decode()}")
break
except socket.timeout:
retry_count += 1
print(f"Timeout {timeout}s, retry...")
if retry_count > max_retry:
print("Max retry reached, communication failed")
cli_sock.close()