任务描述
本关任务:完成一个客户端程序,向服务器端发出请求,传输数据,并设置超时丢包,体验 UDP 的基本连接过程。
相关知识
为了完成本关任务,你需要掌握:
-
创建
socket
对象; -
发送 UDP 数据;
-
接收 UDP 数据;
-
设置超时。
创建socket对象
创建socket
对象是第一步,后续所有的操作都是通过socket
对象完成的。创建对象使用socket()
函数:
s=socket(参数1,参数2) #s就是创建的socket对象
- 参数
1
通常为:- AF_INET:面向网络
- AF_UNIX:面向文件
- 参数
2
通常为:- SOCK_STREAM:面向连接的 TCP 套接字
- SOCK_DGRAM:面向 UDP 的无连接套接字
发送UDP数据
UDP 中一般使用socket
对象的sendto(message , address)
函数发送数据到某个地址:
s.sendto(message, addresss)
-
message
表示待发送的信息。在网络中数据传输使用二进制的形式,因此message
是bytes
类型对象,我们可以使用encode()
函数将字符串类型的数据编码成二进制。 -
在 AF_INET 下,通常以元组
host, port
的形式表示address
,分别代表服务器端 IP 地址和端口号。 -
s 为你所创建的
socket
对象。
接收UDP数据
UDP 中一般使用socket
对象的recvfrom(bufsize)
函数接收来自服务器端的数据。返回值是元组(data,address)
的形式:
data, address = s.recvfrom(bufsize)
-
bufsize
是指定要接收的最大数据量,通常可设为1024
。 -
data
是包含接收数据的二进制串,我们要想获取其中的内容,需要使用decode()
进行解码,将其还原为字符串。 -
address
是发送数据的套接字地址,是元组host, port
。 -
s 为你所创建的
socket
对象。
设置超时
UDP 中一般使用socket
对象的settimeout(timeout)
函数来设置超时:
s.settimeout(1)
-
s 为你所创建的
socket
对象。 -
timeout
是一个浮点数,单位是秒,表示超时的边界值。timeout
的值为None
时表示没有超时期。一般超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作。 -
来自服务器端的报文一旦超时,UDP 就将该报文丢弃。
编程要求
本实训使用python3
进行编程,采用 UDP 方式连接,你需要在右侧编辑器补充代码,完成客户器的功能,具体如下:
-
由于评测系统的服务器端文件和客户端文件位于同一台主机,我们可以使用
localhost
表示服务器端地址。 -
端口号为
56789
。 -
设置超时时长为
1
秒。 -
发送的内容为
Ping x time
,x
表示第几次发送。 -
接收的内容为
Receive x: from y
,x
表示收到第几次的报文,y
为报文来源地址。(具体参考预期输出) -
发生丢包时要有反馈信息,内容为
Sequence x: Request timed out
,x
为第几次的数据报发生丢失。(具体参考预期输出)
测试说明
平台会对你编写的代码进行测试:
预期输出: Sequence 1: Request timed out
Receive 2: from ('127.0.0.1', 12000)
AC代码(如果评测超时,多试几次,头歌这平台很沙比的)
from socket import *
#********* Begin *********#
# 指定服务器地址和端口
addressPort=("127.0.0.1",56789)
#********* End *********#
#********* Begin *********#
# 创建UDP套接字
s=socket(AF_INET,SOCK_DGRAM)
# s.bind(addressPort)
#********* End *********#
#********* Begin *********#
# 设置套接字超时值1秒
s.settimeout(1)
#********* End *********#
i = 0
while i < 2:
try:
# ********* Begin *********#
# 生成数据报,编码为bytes以便发送
data = bytes("Ping " + str(i + 1) + " time",encoding='utf-8')
# ********* End *********#
# ********* Begin *********#
# 将信息发送到服务器
s.sendto(data,("localhost",56789))
# ********* End *********#
# ********* Begin *********#
# 从服务器接收信息,同时也能得到服务器地址,并将其输出
da,address=s.recvfrom(1024)
print("Receive "+str(i+1)+": from "+str(address))
# ********* End *********#
except Exception as e:
# ********* Begin *********#
# 输出超时丢包的反馈信息
print("Sequence "+str(i+1)+": Request timed out")
# ********* End *********#
i = i + 1
#********* Begin *********#
# 关闭该UDP套接字
s.close()
#********* End *********#