面试题答案
一键面试数据传输机制设计
- 序列号与确认机制:为每个发送的数据包添加唯一序列号,接收方收到数据包后,返回带有该序列号的确认包(ACK)。发送方根据ACK确认数据包已被成功接收。
- 窗口机制:采用滑动窗口协议,发送方维护一个发送窗口,窗口内的数据包可以被连续发送而无需等待每个数据包的ACK。接收方维护一个接收窗口,用于接收按序到达的数据包。
连接超时处理
- 设置定时器:发送数据包时启动一个定时器,若在规定时间内未收到对应的ACK,则判定为超时。
- 重传策略:超时后,重传未确认的数据包。可以采用指数退避算法,即每次重传时,将定时器时间加倍,以避免网络拥塞。
重传处理
- 重传队列:维护一个重传队列,存储未收到ACK的数据包及其发送时间。
- 定期检查:定期检查重传队列,对于超时的数据包进行重传。
流量控制
- 接收方通告:接收方在ACK中携带自己的接收窗口大小,告知发送方自己还能接收多少数据。
- 发送方调整:发送方根据接收方通告的窗口大小,动态调整自己的发送窗口,避免发送过多数据导致接收方缓冲区溢出。
代码示例(以Python和select模块为例)
import socket
import select
import time
# 创建UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('localhost', 12345))
# 发送窗口大小
SEND_WINDOW_SIZE = 5
# 接收窗口大小
RECEIVE_WINDOW_SIZE = 5
# 模拟发送数据
def send_data(data, addr):
sequence_number = 0
send_window = []
for i in range(0, len(data), 1024):
packet = data[i:i+1024]
packet = bytes([sequence_number]) + packet
send_window.append((packet, time.time()))
sock.sendto(packet, addr)
sequence_number += 1
if len(send_window) >= SEND_WINDOW_SIZE:
process_send_window(send_window, addr)
# 处理剩余数据包
while send_window:
process_send_window(send_window, addr)
# 处理发送窗口
def process_send_window(send_window, addr):
ready_to_read, _, _ = select.select([sock], [], [], 1)
if sock in ready_to_read:
ack, _ = sock.recvfrom(1024)
sequence_number = ack[0]
for packet, _ in send_window:
if packet[0] == sequence_number:
send_window.remove((packet, time.time()))
break
for packet, send_time in send_window:
if time.time() - send_time > 5: # 超时时间5秒
sock.sendto(packet, addr)
send_window.remove((packet, send_time))
send_window.append((packet, time.time()))
# 模拟接收数据
def receive_data():
receive_window = []
expected_sequence_number = 0
while True:
ready_to_read, _, _ = select.select([sock], [], [])
if sock in ready_to_read:
packet, addr = sock.recvfrom(1024)
sequence_number = packet[0]
if sequence_number == expected_sequence_number:
receive_window.append(packet[1:])
expected_sequence_number += 1
# 处理接收窗口中的数据
if len(receive_window) >= RECEIVE_WINDOW_SIZE:
process_receive_window(receive_window)
receive_window = []
sock.sendto(bytes([sequence_number]), addr) # 发送ACK
else:
# 处理乱序包
pass
# 处理接收窗口
def process_receive_window(receive_window):
data = b''.join(receive_window)
print('Received data:', data.decode('utf-8'))
# 启动发送和接收线程
import threading
send_thread = threading.Thread(target=send_data, args=(b'Hello, world!', ('localhost', 54321)))
receive_thread = threading.Thread(target=receive_data)
send_thread.start()
receive_thread.start()
send_thread.join()
receive_thread.join()
以上代码展示了在UDP网络环境下,通过IO多路复用技术(select
模块)实现可靠数据传输的关键思路,包括序列号与确认机制、连接超时、重传以及流量控制等功能。实际应用中,还需根据具体需求进一步优化和完善。