实现基于UDP的ping程序

套接字编程作业2:UDPping程序

作业描述

《计算机网络:自顶向下方法》中第二章末尾给出了此编程作业的简单描述:

在这个编程作业中,你将用Python编写一个客户ping程序。该客户将发送一个简单的ping报文,接受一个从服务器返回的pong报文,并确定从该客户发送ping报文到接收到pong报文为止的时延。该时延称为往返时延(RTT)。由该客户和服务器提供的功能类似于在现代操作系统中可用的标准ping程序,然而,标准的ping使用互联网控制报文协议(ICMP)(我们将在第4章中学习ICMP)。此时我们将创建一个非标准(但简单)的基于UDP的ping程序。

你的ping程序经UDP向目标服务器发送10个ping报文,对于每个报文,当对应的pong报文返回时,你的客户要确定和打印RTT。因为UDP是一个不可靠协议,由客户发送的分组可能会丢失。为此,客户不能无限期地等待对ping报文的回答。客户等待服务器回答的时间至多为1秒;如果没有收到回答,客户假定该分组丢失并相应地打印一条报文。

在此作业中,我们给出服务器的完整代码(在配套网站中可以找到。你的任务是编写客户代码,该代码与服务器代码非常类似。建议你先仔细学习服务器的代码,然后编写你的客户代码,可以不受限制地从服务器代码中剪贴代码行。

可选练习:

  1. 目前,程序计算每个数据包的往返时间(RTT),并单独打印出来。请按照标准ping程序的模式修改。您需要在客户端每次ping后显示最小,最大和平均RTT。另外,还需计算丢包率(百分比)。
  2. UDP Ping的另一个类似的应用是UDP Heartbeat。心跳可用于检查应用程序是否已启动并运行,并报告单向丢包。客户端在UDP数据包中将一个序列号和当前时间戳发送给正在监听客户端心跳的服务器。服务器收到数据包后,计算时差,报告丢包(若发生)。如果心跳数据包在指定的一段时间内丢失,我们可以假设客户端应用程序已经停止。实现UDP Heartbeat(客户端和服务器端)。您需要修改给定的UDPPingerServer.py和您自己的UDP ping客户端。

需求实现

首先建立一个UDP套接字,并指定目的IP地址和端口。如何建立UDP连接在我的另外一篇文章有详细的介绍

UDP和TCP套接字编程实现及原理阐述

然后使用一个循环来发送数据包,共循环10次。由于需要对往返时间进行计算,所以需要sendto()前和recvfrom()后提取时间。两次相减,可得到每个消息的往返时延(RTT)。对于其他的信息,设置相关变量进行记录即可,大家可以使用其他的方法进行数据的采集最后分析显示结果。

编写代码及解释

(1)客户端请求
# UDPPingClient.py
from socket import *
import time

serverName = '113.54.200.50'  # 服务器地址
serverPort = 12000  # 服务器指定的端口
clientSocket = socket(AF_INET, SOCK_DGRAM)  # 创建UDP套接字
clientSocket.settimeout(1)  # 设置套接字超时值为1秒
timeList = []  # 创建空列表,存放TTL
totalReq = 10  # 设置发送报文数
loseReq = 0    # 丢包数,为了后面计算丢包率
totalTime = 0  # 总时间,方便后面计算平均往返时间

for i in range(0, totalReq):
    sendTime = time.time()
    message = ('Ping %d %s' % (i + 1, sendTime)).encode()  # 生成数据报,编码为bytes以便发送
    try:
        clientSocket.sendto(message, (serverName, serverPort))  # 将信息发送到服务器
        modifiedMessage, serverAddress = clientSocket.recvfrom(1024)  # 从服务器接收信息,同时也能得到服务器地址
        TTL1 = time.time() - sendTime  # 计算往返时间
        timeList.append(TTL1)  # 将TTL放入列表,方便后面进行数据统计
        totalTime += TTL1
        print('Request sequence %d: Reply from %s    RTT = %.5fs' % (i + 1, serverName, TTL1))  # 显示信息
    except Exception as e:  # 接收多种异常,给每一个进入到此 except 块的异常,起一个统一的别名 e
        TTL2 = time.time() - sendTime  # 计算往返时间
        timeList.append(TTL2)  # 将TTL放入列表,方便后面进行数据统计
        loseReq += 1
        totalTime += TTL2
        print('Request sequence %d: Request timed out' % (i + 1))

# ping后显示最小,最大和平均RTT。另外,还需计算丢包率(百分比)
print('\n minRTT: %0.5fs\t maxRTT: %0.5fs\t avgRTT: %0.5fs'
      % (min(timeList), max(timeList), totalTime/len(timeList)))
print('\n packetLoss percent: {:.2%}'.format(loseReq/totalReq))

clientSocket.close()  # 关闭套接字
(2)服务端设置
# UDPPingerServer.py
# 生成随机丢失的数据包,导入随机数包
from socket import *
import random

# 创建UDP套接字,第一参数表示使用IPV4,第二参数指示套接字为UDP类型
serverSocket = socket(AF_INET, SOCK_DGRAM)
# 申请端口号,并将IP地址一起绑定到套接字;目的地址包含目的端IP和端口号
serverSocket.bind(('', 12000))

# 服务器会一直等待分组到达
while True:
	# 产生一个(0,10)的随机整数
	rand = random.randint(0, 10)
	# Receive the client packet along with the address it is coming from
	# 接收客户端信息,从客户端接收UDP数据报
	# UDP是无连接的。sendto(),是把UDP数据报发给指定地址;recvfrom()是从指定地址接收UDP数据报。
	message, address = serverSocket.recvfrom(1024)
	# 将收到的数据转为大写
	message = message.upper()

	# 如果rand小于4,则我们认为数据包丢失并且不响应
	if rand < 4:
		continue
	# 把更改后的UDP数据报发给指定地址,地址为上面的客户端的地址
	serverSocket.sendto(message, address)

运行结果

服务器端:

在一台主机上运行UDPPingerServer.py,作为接收ping程序数据的服务器。

客户端:

在另一台主机上运行UDPPingClient.py,实验结果如下:

在这里插入图片描述

(1)通过ping程序经UDP向目标服务器发送10个ping报文,对于每个报文,当对应的pong报文返回时,你的客户要确定和打印RTT。因为UDP是一个不可靠协议,由客户发送的分组可能会丢失。为此,客户不能无限期地等待对ping报文的回答。客户等待服务器回答的时间至多为1秒;如果没有收到回答,客户假定该分组丢失并相应地打印一条丢失报文

(2)目前,程序计算每个数据包的往返时间(RTT),并单独打印出来。按照标准ping程序的模式修改。在客户端每次ping后显示最小,最大和平均RTT。另外,还需计算丢包率(百分比)。

### 回答1: 编程实现基于UDPping可以通过以下步骤来完成: 1. 导入所需的库:首先,需要导入Pythonsocket库,以便在程序中使用UDP套接字。 2. 创建UDP套接字:使用socket库创建一个UDP套接字,可以通过调用`socket.socket(socket.AF_INET, socket.SOCK_DGRAM)`来实现。 3. 设置超时时间:使用`socket.settimeout()`函数来设置套接字的超时时间,以便在接收响应时等待的最长时间。 4. 发送ping消息:使用套接字的`sendto()`函数来发送ping消息。可以选择发送一个特定的字符串作为ping消息。 5. 接收响应:使用套接字的`recvfrom()`函数来接收对ping消息的响应。可以选择接收一个特定大小的字节流。 6. 计算往返时间:从收到的响应中获取发送ping消息的时间戳,然后计算往返时间(RTT)。 7. 打印结果:根据ping的结果,打印出发送ping消息的IP地址、往返时间和响应状态。 8. 关闭套接字:最后,使用套接字的`close()`函数来关闭UDP套接字。 一个简单的基于UDPping程序的示例代码如下: ```python import socket import time def udp_ping(hostname, port): try: # 创建UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 设置超时时间为1秒 sock.settimeout(1) # 发送ping消息 start_time = time.time() sock.sendto(b'ping', (hostname, port)) # 接收响应 data, addr = sock.recvfrom(1024) end_time = time.time() # 计算往返时间 rtt = end_time - start_time # 打印结果 print('Ping from', addr[0], 'RTT:', rtt, 's') except socket.timeout: # 超时处理 print('Ping request timed out') finally: # 关闭套接字 sock.close() # 测试 udp_ping('localhost', 8080) ``` 这是一个简单的基于UDPping程序,它通过发送ping消息并等待响应来计算往返时间。在接收响应时,如果超过了设定的超时时间,程序将打印出"Ping request timed out"表示超时。 请注意,这只是一个基本示例,实际上,可以根据需要进行更多的改进和扩展,例如通过发送多个ping消息进行统计或添加其他ping功能。 ### 回答2: 基于UDP(用户数据报协议)实现ping功能需要以下步骤: 1. 导入必要的库:首先需要导入socket库来实现网络连接和发送/接收数据。 2. 创建一个UDP套接字:使用socket库的`socket(AF_INET, SOCK_DGRAM)`函数来创建一个UDP套接字。 3. 设定服务器地址和端口:使用`bind()`函数将服务器的IP地址和端口绑定到套接字上。 4. 设置超时时间:使用`settimeout()`函数设置等待数据的超时时间,即等待服务器响应的最长时间。 5. 发送和接收数据:使用`sendto()`函数将ping请求发送给服务器。然后使用`recvfrom()`函数等待服务器的响应。如果超过超时时间,服务器未响应,会抛出异常。如果接收到响应,计算往返时间(RTT)。 7. 输出结果:在控制台输出服务器的IP地址,发送/接收的数据包的大小和往返时间。 以下是一个示例的基于UDPping程序: ```python import socket import time # 创建UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 设定服务器地址和端口 server_address = ('127.0.0.1', 12345) sock.bind(server_address) # 设置超时时间 sock.settimeout(1) # 发送和接收数据 for i in range(10): start_time = time.time() # 发送ping请求 message = f'Ping {i}'.encode() sock.sendto(message, server_address) try: # 等待服务器的响应 data, address = sock.recvfrom(1024) end_time = time.time() # 计算往返时间 rtt = end_time - start_time # 输出结果 print(f'Reply from {address[0]}: bytes={len(data)}, time={round(rtt * 1000, 2)}ms') except socket.timeout: print('Request timed out') # 关闭套接字 sock.close() ``` 此示例会向服务器发送10个ping请求,并等待服务器的响应。如果超过1秒钟没有收到响应,会输出"Request timed out"。收到响应后,会输出服务器的IP地址、发送/接收的数据包大小以及往返时间。 ### 回答3: 编程实现基于UDPping可以通过以下步骤来完成: 1. 导入必要的库和模块,例如socket库用于实现网络通信。 2. 创建一个UDP套接字对象,可以使用socket库中的socket函数来实现。 3. 设置超时时间,以便在等待服务器响应时能够控制等待时间。 4. 循环发送ping消息给服务器,并接收服务器的响应。 5. 在发送ping消息之前,记录当前时间作为开始时间。 6. 通过套接字对象的sendto函数将ping消息发送到服务器的特定地址和端口。 7. 接收服务器的响应消息,并记录接收到响应时的时间。 8. 计算往返时间(RTT)时间,即接收到响应时的时间减去发送时的时间。 9. 打印出接收到的响应消息、往返时间和服务器的地址和端口信息。 10. 重复步骤4-9,直到达到指定的次数或设置了终止ping的条件。 11. 统计和计算平均往返时间和丢包率等相关统计信息。 12. 关闭套接字。 编程实现基于UDPping可以通过上述步骤来完成。这个程序可以用于测试服务器的可用性和计算网络的RTT等指标。在实际使用中,还可以根据具体的需求对程序进行扩展和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值