任务描述
本关任务:创建一个非标准的基于 UDP 的ping
程序,需要输出数据包的源主机 IP 地址以及往返时延(RTT)。
相关知识
为了完成本关任务,你需要回顾第一个关卡的具体内容,包括:
- 创建
socket
对象; - 发送 UDP 数据;
- 接收 UDP 数据;
- 设置超时
如果已经忘记了相关的内容,请返回第一关进行复习。
除此之外,你还需要掌握:
- Ping 的基本工作原理
- 计算往返时延 RTT
Ping 的基本工作原理
-
PING
(Packet Internet Groper)
:因特网包探索器,用于测试网络连接量的程序。在现代操作系统中标准ping
程序是一个网络诊断工具,客户端发送一个ping
报文,接受一个从服务器返回的pong
报文,标准的ping
使用互联网控制报文协议( ICMP )。 -
在本关卡中,您将创建一个非标准的基于 UDP 的
ping
程序。您的ping
程序经 UDP 向目标服务器发送10
个ping
报文,对于每个报文,当对应的pong
报文返回时,你的客户要确定和打印 RTT。因为 UDP 是一个不可靠协议,由客户发送的分组可能会丢失。为此,客户不能无限期地等待对ping
报文的回答。客户等待服务器回答的时间至多为1
秒,如果没有收到回答,客户假定该分组丢失并相应地打印一条反馈信息。
计算往返时延 RTT
-
RTT
(Round-Trip Time)
:往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延:RTT = 收到数据的时间 - 发送数据的时间
-
往返延时由三个部分决定:即链路的传播时间、末端系统的处理时间以及路由器的缓存中的排队和处理时间。其中,前面两个部分的值作为一个TCP连接相对固定,路由器中缓存的排队和处理时间会随着整个网络拥塞程度的变化而变化。所以 RTT 的变化在一定程度上反映了网络拥塞程度的变化。
-
本实验,你需要确定从客户端发送
ping
报文到接收到pong
报文为止的时延。 -
我们需要使用
python
中的time
模块,该模块中的time()
函数可以提供当前时间的时间戳:time.time() #表示当前时间的时间戳
编程要求
本实训使用python3
进行编程,客户端将采用 UDP 方式连接服务器。你需要建立一个 UDP 套接字,并指定目的IP地址和端口,随之使用一个循环来发送数据包,共循环10
次,你需要在右侧编辑器补充代码,完成客户器的功能,具体如下:
-
由于评测系统的服务器端文件和客户端文件位于同一台主机,我们可以使用
localhost
表示服务器端地址。 -
端口号为
56789
。 -
设置超时时长为
1
秒。 -
客户端发送的内容为
Ping x time
,x
表示第几次发送。(你不需要将发送内容输出) -
接收的内容为
Receive x: Reply from y RTT = z
,你需要将其输出,其中x
表示收到第几次的报文,y
是服务器的 IP 地址,该地址不包括端口号,z
是往返时延 RTT,单位为s
,并且保留小数点后两位有效数字,输出时需要加上单位,具体参考预期输出。 -
发生丢包时要有反馈信息,并且需要输出,内容为
Sequence x: Request timed out
,x
表示第几个数据包报发生丢失,具体参考预期输出。
测试说明
平台会对你编写的代码进行测试:
预期输出: Receive 1: Reply from 127.0.0.1 RTT = 0.80s
Receive 2: Reply from 127.0.0.1 RTT = 0.50s
Receive 3: Reply from 127.0.0.1 RTT = 0.80s
Receive 4: Reply from 127.0.0.1 RTT = 0.50s
Sequence 5: Request timed out
Receive 6: Reply from 127.0.0.1 RTT = 0.20s
Receive 7: Reply from 127.0.0.1 RTT = 0.50s
Receive 8: Reply from 127.0.0.1 RTT = 0.80s
Receive 9: Reply from 127.0.0.1 RTT = 0.80s
Receive 10: Reply from 127.0.0.1 RTT = 0.50s
开始你的任务吧,祝你成功!
from socket import *
import time
#********* Begin *********#
# 指定服务器地址和端口
addressPort = ("localhost", 56789)
#********* End *********#
#********* Begin *********#
# 创建UDP套接字
s = socket(AF_INET, SOCK_DGRAM)
#********* End *********#
#********* Begin *********#
# 设置套接字超时值1秒
s.settimeout(1)
#********* End *********#
i = 1
while i <= 10:
sendTime = time.time() # 记录发送ping报文的当前时间戳
try:
# ********* Begin *********#
# 生成数据报,编码为bytes,并发送给服务器
data = bytes("Ping " + str(i) + " time", encoding='utf-8')
s.sendto(data, addressPort)
# ********* End *********#
# ********* Begin *********#
# 从服务器接收信息,同时也能得到来自服务器的地址,需要输出该地址,(不要输出端口号!)
# 并且需要计算和输出RTT,具体见编程要求
data, server_address = s.recvfrom(1024)
end_time = time.time() # 记录接收时间
rtt = round(end_time - sendTime, 2) # 计算往返时延
print('Receive %d: Reply from %s RTT = %.2fs' % (i, server_address[0], rtt))
# ********* End *********#
except Exception as e:
# ********* Begin *********#
# 输出超时丢包的反馈信息。
print(f'Sequence {i}: Request timed out')
# ********* End *********#
i = i + 1
#********* Begin *********#
# 关闭该UDP套接字
s.close()
#********* End *********#