计算机网络第二章:作业 2: UDP ping 程序

套接字编程作业 2:UDP Ping 程序

问题描述:

在这个实验中,你将通过Python使用UDP套接字编程,编写一个ping程序。Ping程序是用来测试网络延迟的工具,客户端通过发送请求到服务器,然后计算往返时间(RTT),并处理可能的丢包。作业的主要任务是:

  1. 编写一个UDP客户端,向服务器发送10个ping请求。
  2. 服务器会根据收到的请求返回响应,但30%的请求会被随机丢弃以模拟丢包。
  3. 客户端应处理超时情况,超时阈值为1秒。
  4. 每次ping请求后,客户端应输出收到的响应或超时消息,并显示往返时间(RTT)。

你需要实现的客户端程序功能类似于标准的ping命令,但使用的是UDP协议,而不是ICMP协议。

问题解决流程:

  1. 理解UDP协议的特点

    • UDP是一种无连接、轻量级但不可靠的传输协议,数据包可能会丢失,不保证数据的到达顺序。
    • 在Ping程序中,我们使用UDP,因为其简单且能模拟不可靠的网络通信。
  2. 服务器端实现

    • 我们提供了一个服务器端程序UDPPingerServer.py,它接收来自客户端的请求,随机丢弃30%的请求,剩下的请求则返回给客户端。
    • 你需要在本地或远程服务器上运行该服务器程序,然后实现客户端程序与其通信。
  3. 客户端功能要求

    • 使用UDP向服务器发送10次ping请求,每次请求中包含当前的发送时间。
    • 服务器返回响应后,计算该请求的往返时间(RTT)。
    • 如果请求超过1秒未收到响应,则显示"Request timed out"。
    • 最终输出每次ping的RTT或者超时消息。

步骤 1:服务器代码

服务器代码已经提供,先确保它在本地或远程服务器上运行。

python 复制代码
# UDPPingerServer.py 
from socket import * 
import random

# 创建一个UDP套接字
serverSocket = socket(AF_INET, SOCK_DGRAM)
# 绑定服务器的IP地址和端口号
serverSocket.bind(('', 12000))

while True:
    # 生成一个随机数,用于模拟丢包
    rand = random.randint(0, 10)
    # 接收客户端消息和地址
    message, address = serverSocket.recvfrom(1024)
    # 将收到的消息转换为大写
    message = message.upper()
    # 如果随机数小于4,模拟丢包,不返回任何消息
    if rand < 4:
        continue
    # 否则,将消息返回给客户端
    serverSocket.sendto(message, address)
  • 该服务器程序使用UDP协议监听端口12000,并随机丢弃30%的客户端请求。

步骤 2:客户端代码

我们现在需要编写客户端程序,它将向服务器发送10个ping请求,并显示每次请求的结果,包括往返时间或超时。

python 复制代码
import time
from socket import *

# 创建UDP套接字
clientSocket = socket(AF_INET, SOCK_DGRAM)
# 设置超时时间为1秒
clientSocket.settimeout(1)

# 服务器的地址和端口
serverName = 'localhost'  # 本地运行时使用 'localhost'
serverPort = 12000

# 发送10次ping请求
for sequence_number in range(1, 11):
    # 获取当前时间戳
    sendTime = time.time()
    # 构造ping消息
    message = f'Ping {sequence_number} {sendTime}'
    
    try:
        # 向服务器发送消息
        clientSocket.sendto(message.encode(), (serverName, serverPort))
        
        # 等待服务器响应,超时1秒
        response, serverAddress = clientSocket.recvfrom(1024)
        
        # 计算RTT
        rtt = time.time() - sendTime
        # 打印服务器返回的消息和RTT
        print(f'Received from server: {response.decode()} RTT = {rtt:.4f} seconds')
    
    except timeout:
        # 超时处理
        print('Request timed out')

# 关闭套接字
clientSocket.close()

代码解析:

  1. 创建UDP套接字clientSocket = socket(AF_INET, SOCK_DGRAM) 使用UDP协议,适合无连接的通信。
  2. 设置超时clientSocket.settimeout(1) 设置接收数据包的超时时间为1秒,如果在1秒内未收到响应,则抛出timeout异常。
  3. 发送ping消息clientSocket.sendto(message.encode(), (serverName, serverPort)) 向服务器发送包含序列号和时间戳的ping消息。
  4. 接收服务器响应clientSocket.recvfrom(1024) 接收服务器返回的消息,并计算消息的往返时间(RTT)。
  5. 超时处理:如果未收到响应,客户端会输出"Request timed out"。

步骤 3:运行程序

1. 运行服务器:

在本地或远程服务器上运行提供的服务器代码:

bash 复制代码
python UDPPingerServer.py
2. 运行客户端:

在另一个终端窗口中运行客户端代码:

bash 复制代码
python UDPPingerClient.py

你会看到客户端向服务器发送10次ping请求的输出,类似于以下结果:

复制代码
Received from server: PING 1 1663261625.64255 RTT = 0.0021 seconds
Received from server: PING 2 1663261626.64305 RTT = 0.0020 seconds
Request timed out
Received from server: PING 4 1663261628.64400 RTT = 0.0021 seconds
...
  • 如果服务器丢弃了请求,客户端会显示Request timed out
  • 如果服务器返回了响应,客户端会显示往返时间(RTT)。

可选练习1

客户端程序需要在发送10次Ping请求后计算最小、最大和平均RTT,同时计算丢包率。我们可以通过保存每次Ping的RTT值,最后计算这些统计数据。具体步骤如下:

实现步骤

  1. 存储每次Ping的RTT:为RTT创建一个列表,每次接收到响应时,将RTT添加到该列表中。
  2. 统计丢包情况:为超时次数创建一个计数器,每次超时时递增。
  3. 计算最小、最大和平均RTT:在发送完所有Ping请求后,通过列表计算最小值、最大值和平均值。
  4. 计算丢包率:丢包率 = (丢失的包数 / 总包数)× 100%。

修改后的代码

python 复制代码
import time
from socket import *

# 创建UDP套接字
clientSocket = socket(AF_INET, SOCK_DGRAM)
# 设置超时时间为1秒
clientSocket.settimeout(1)

# 服务器的地址和端口
serverName = 'localhost'  # 本地运行时使用 'localhost'
serverPort = 12000

# 初始化变量
rtt_list = []  # 存储每次成功Ping的RTT
timeout_count = 0  # 记录超时的次数
total_pings = 10  # 发送的Ping总次数

# 发送10次ping请求
for sequence_number in range(1, total_pings + 1):
    # 获取当前时间戳
    sendTime = time.time()
    # 构造ping消息
    message = f'Ping {sequence_number} {sendTime}'
    
    try:
        # 向服务器发送消息
        clientSocket.sendto(message.encode(), (serverName, serverPort))
        
        # 等待服务器响应,超时1秒
        response, serverAddress = clientSocket.recvfrom(1024)
        
        # 计算RTT
        rtt = time.time() - sendTime
        rtt_list.append(rtt)  # 将RTT加入列表
        
        # 打印服务器返回的消息和RTT
        print(f'Received from server: {response.decode()} RTT = {rtt:.4f} seconds')
    
    except timeout:
        # 超时处理,计数器增加
        print('Request timed out')
        timeout_count += 1

# 关闭套接字
clientSocket.close()

# 如果有成功的Ping,则计算最小、最大和平均RTT
if rtt_list:
    min_rtt = min(rtt_list)
    max_rtt = max(rtt_list)
    avg_rtt = sum(rtt_list) / len(rtt_list)
    
    print(f'\n--- Ping statistics ---')
    print(f'{total_pings} packets transmitted, {len(rtt_list)} packets received, '
          f'{timeout_count / total_pings * 100:.1f}% packet loss')
    print(f'rtt min/avg/max = {min_rtt:.4f}/{avg_rtt:.4f}/{max_rtt:.4f} seconds')

else:
    print(f'\n--- Ping statistics ---')
    print(f'{total_pings} packets transmitted, 0 packets received, 100.0% packet loss')

代码解析

  1. rtt_list:这是一个列表,用于存储每次成功的RTT值。当接收到响应时,将RTT值添加到该列表中。
  2. timeout_count:这是一个计数器,用于记录超时(丢包)的次数。每当请求超时时,计数器会加1。
  3. RTT计算 :程序结束后,检查rtt_list是否为空。如果有接收到的Ping响应,则计算最小、最大和平均RTT,并打印出来。
  4. 丢包率计算 :丢包率通过timeout_count / total_pings * 100计算,表示为百分比形式。

输出示例

假设服务器响应如下:

复制代码
Received from server: PING 1 1663261625.64255 RTT = 0.0021 seconds
Request timed out
Received from server: PING 3 1663261626.64305 RTT = 0.0020 seconds
Request timed out
Received from server: PING 5 1663261627.64400 RTT = 0.0021 seconds
...

--- Ping statistics ---
10 packets transmitted, 6 packets received, 40.0% packet loss
rtt min/avg/max = 0.0020/0.0021/0.0022 seconds

通过这些修改,客户端程序在完成所有Ping操作后,会输出最小、最大和平均RTT,并计算出丢包率。这种行为模拟了标准ping命令的功能,提供了更加详细的网络通信统计信息。

相关推荐
ulias21230 分钟前
Linux系统中的权限问题
linux·运维·服务器
青花瓷2 小时前
Ubuntu下OpenClaw的安装(豆包火山API版)
运维·服务器·ubuntu
问简2 小时前
docker 镜像相关
运维·docker·容器
Dream of maid3 小时前
Linux(下)
linux·运维·服务器
齐鲁大虾3 小时前
统信系统UOS常用命令集
linux·运维·服务器
Benszen3 小时前
Docker容器化技术实战指南
运维·docker·容器
ZzzZZzzzZZZzzzz…3 小时前
Nginx 平滑升级:从 1.26.3 到 1.28.0,用户无感知
linux·运维·nginx·平滑升级·nginx1.26.3·nginx1.28.0
一叶知秋yyds5 小时前
Ubuntu 虚拟机安装 OpenClaw 完整流程
linux·运维·ubuntu·openclaw
专吃海绵宝宝菠萝屋的派大星5 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
斯普信云原生组5 小时前
Prometheus 环境监控虚机 Redis 方案(生产实操版)
运维·docker·容器