实现思路
- 添加序列号:为每个发送的UDP数据包添加一个唯一的序列号。接收方根据序列号判断数据包是否按序到达,并且可以检测到丢失的数据包。
- 确认机制:接收方接收到数据包后,向发送方发送一个确认包(ACK),ACK包中包含接收到的数据包的序列号。
- 重传机制:发送方在发送数据包后,启动一个定时器。如果在定时器超时之前没有收到对应的ACK,就重传该数据包。
- 窗口机制:引入发送窗口,限制发送方在未收到ACK的情况下可以连续发送的数据包数量,避免过多重传导致网络拥塞。
关键代码片段
发送方代码
import socket
import time
# 创建UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 10000)
# 发送窗口大小
window_size = 5
# 数据包序列号
sequence_number = 0
# 已发送但未确认的数据包
unacknowledged_packets = {}
def send_packet(data, seq_num):
packet = f"{seq_num}:{data}".encode('utf-8')
sock.sendto(packet, server_address)
unacknowledged_packets[seq_num] = {
'data': data,
'sent_time': time.time()
}
while True:
while sequence_number - min(unacknowledged_packets.keys()) < window_size if unacknowledged_packets else True:
data = input("Enter data to send (type 'exit' to quit): ")
if data.lower() == 'exit':
break
send_packet(data, sequence_number)
sequence_number += 1
# 检查是否有超时的数据包需要重传
current_time = time.time()
for seq_num, packet_info in list(unacknowledged_packets.items()):
if current_time - packet_info['sent_time'] > 1: # 超时时间1秒
print(f"Timeout for sequence number {seq_num}, retransmitting...")
send_packet(packet_info['data'], seq_num)
packet_info['sent_time'] = current_time
try:
sock.settimeout(0.1) # 设置接收ACK的超时时间
ack, _ = sock.recvfrom(1024)
ack_seq_num = int(ack.decode('utf-8'))
if ack_seq_num in unacknowledged_packets:
del unacknowledged_packets[ack_seq_num]
print(f"Received ACK for sequence number {ack_seq_num}")
except socket.timeout:
continue
if data.lower() == 'exit':
break
sock.close()
接收方代码
import socket
# 创建UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DUDP)
server_address = ('localhost', 10000)
sock.bind(server_address)
expected_sequence_number = 0
while True:
data, address = sock.recvfrom(1024)
seq_num, received_data = data.decode('utf-8').split(':', 1)
seq_num = int(seq_num)
if seq_num == expected_sequence_number:
print(f"Received data: {received_data}")
ack = str(seq_num).encode('utf-8')
sock.sendto(ack, address)
expected_sequence_number += 1
else:
print(f"Received out - of - order packet with sequence number {seq_num}")