确保数据正确到达服务器端及处理网络丢包
- 使用校验和:在UDP协议中,虽然本身有校验和,但为了额外确保数据完整性,我们可以在应用层再计算一次校验和。发送端计算数据的校验和并一同发送,接收端重新计算校验和并与接收到的校验和对比。
- 设置超时重传:如果在一定时间内没有收到服务器的确认(ACK),就重新发送数据。
- 序列号:为每个数据包添加序列号,以便接收端可以按序重组数据,并且可以检测到丢包。
代码示例
import socket
import hashlib
import time
# UDP 客户端
def udp_client():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 10000)
message = "Hello, Server!".encode('utf-8')
sequence_number = 0
while True:
# 计算校验和
checksum = hashlib.md5(message + str(sequence_number).encode('utf-8')).hexdigest()
packet = f"{sequence_number}:{checksum}:{message.decode('utf-8')}".encode('utf-8')
client_socket.settimeout(1) # 设置超时时间为1秒
try:
client_socket.sendto(packet, server_address)
start_time = time.time()
while True:
data, server = client_socket.recvfrom(1024)
received_sequence, received_checksum = data.decode('utf-8').split(':')[:2]
if received_sequence == str(sequence_number) and received_checksum == checksum:
print("数据正确到达服务器并收到确认")
break
if time.time() - start_time > 1:
print("超时,重新发送")
break
except socket.timeout:
print("超时,重新发送")
continue
sequence_number += 1
time.sleep(1) # 间隔1秒发送下一个包
client_socket.close()
if __name__ == "__main__":
udp_client()
代码说明
- 校验和计算:使用
hashlib.md5
计算包含序列号和数据的校验和。
- 设置超时:使用
client_socket.settimeout(1)
设置每次发送数据后的等待超时时间为1秒。
- 重传机制:如果在超时时间内没有收到正确的确认信息,重新发送数据包。
- 序列号:每次发送数据时,序列号加1,用于数据包的标识和排序。