MST
星途 面试题库

面试题:Python UDP服务器数据可靠性处理

在Python实现的UDP服务器中,由于UDP本身的不可靠性,如何通过编程手段提高数据传输的可靠性,比如实现类似TCP的确认机制,描述具体实现思路并给出关键代码片段。
47.0万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 添加序列号:为每个发送的UDP数据包添加一个唯一的序列号。接收方根据序列号判断数据包是否按序到达,并且可以检测到丢失的数据包。
  2. 确认机制:接收方接收到数据包后,向发送方发送一个确认包(ACK),ACK包中包含接收到的数据包的序列号。
  3. 重传机制:发送方在发送数据包后,启动一个定时器。如果在定时器超时之前没有收到对应的ACK,就重传该数据包。
  4. 窗口机制:引入发送窗口,限制发送方在未收到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}")