UDP socket实现ack,感知丢包重传|青训营

239 阅读1分钟

作业要求:

  1. 学会 UDP socket 编程

  2. 先从简单的 ack 学习,客户端等待 ack 再发包

  3. 什么时候客户端认为是丢包?

  4. 重传怎么考虑效率?

  5. 能不能不阻塞只传丢掉的中间的段?


实现部分

客户端向服务器端发送数据包,服务器端若成功接收,则向客户端返回确认信息,若客户端在等待时间内未收到服务器端发送的确认信息,则重新发送。

客户端

创建UDP socketsocket.socket(socket.AF_INET, socket.SOCK_DGRAM)

参数1:AddressFamil 创建套接字所用的协议族

  • AF_INET:IPv4网络协议
  • AF_INET:IPv6网络协议

参数2:Type

  • SOCK_STREAM:流式套接字,主要用于TCP协议
  • SOCK_DGRAM:数据报套接字,主要用于UDP协议
# 创建 UDP socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 关闭
client_socket.close()

通过设定超时时间,来判断数据包是否丢失

# 等待 ACK,设置超时时间为 2 秒
client_socket.settimeout(2)

print(f"Timeout: No ACK received for packet {i}. Resending...")
time.sleep(1)

超时重传 如果超时了,则重新发送。假定最多发送三次,三次未成功则为发送失败。

max_retry_times = 3
retry_time = 0
while retry_time < max_retry_times:
    try:
        pass
        # 成功发送,就退出循环
        break
    except socket.timeout:
        retry_time += 1
        time.sleep(1)
    retry_time = 0    

发送数据包client_socket.sendto(message.encode(), server_address)

接收数据包ack, address = client_socket.recvfrom(1024)


服务器端

绑定服务器地址和端口

server_address = ("localhost",8000)
server_socket.bind(server_address)

模拟随机丢包

if random.random() < 0.3:
    continue

解析序列号并发送确认号

seq_num = int(data.decode().split()[2])
ack_num = seq_num + 1
server_socket.sendto(ack_num.to_bytes(4, byteorder='big'), client_address)

注:客户端的地址通过接收其发送的数据携带。

问题3: 什么时候客户端认为是丢包? (谈谈网络通信中的 ACK、NACK 和 REX - 知乎 (zhihu.com))

1. 停等协议 发送方每次只发送一个包,同时启动一个定时器。如果定时器超时依然没有收到这个包的 ACK,则认为丢包,重传这个包。如果收到 ACK,则重置定时器并发送下一个包。

问题:丢包的判断和传输效率非常低

2. 连续 ARQ 协议 & 滑窗协议

发送方维持着一个一定大小的发送窗口,位于发送窗口内的所有包可以连续发送出去,中途不需要依次等待对方的 ACK 确认。

接收方通常采用 积累确认模式,即不必对每一个包逐个发送 ACK,而是在连续收到几个包后,对顺序到达的最后一个包序号发送 ACK,表示:这个包及之前的所有包都已正确收到了。

积累确认模式 的缺点:乱序比较严重的网络下,效率非常低,部分已经送到但没有按照顺序送达的包也必须重传。

改进方案:选择性重传(注:KCP/SRT 协议有实现):对于顺序的包,发送积累确认;跳跃的包,发送 ACK;发送端只重传真正丢失的数据包。

3. 快速重传

使用 ACK 机制的传输协议,通常在发送端等到某个数据包的 ACK 超时后,才会重传数据包,不够及时。

快速重传:如果接收端接收到了序号跳跃的数据包,则立即给发送方发送最后一个连续的数据包的 ACK(重复确认) 。如果发送端收到连续 3 个重复确认,则认为该 ACK 的下一个数据包丢失了,并立即重传该丢失的数据包。

4. NACK

接收方定时把所有未收到的包序号通过反馈报文通知到发送方进行重传。

带来的改进:减少的反馈包的频率和带宽占用,同时也能比较及时地通知发送方进行丢包重传


测试

image.png

image.png

问题4:重传怎么考虑效率?

  • RTT:数据包的往返时间
  • RTO:超时重传时间 设定合适的RTO

问题5:能不能不阻塞只传丢掉的中间的段

可以。