基于UDP的基础上实现保序和可靠传输

UDP(User Datagram Protocol)是一种无连接的、尽力而为的传输层协议。它不保证数据包的顺序和可靠性,因此在某些应用场景下,需要在UDP的基础上实现保序和可靠传输。以下是实现这些功能的一些常见方法和示例代码。

实现保序和可靠传输的基本思路

  1. 序列号:为每个数据包分配一个唯一的序列号,以便接收方能够按序重组数据包。
  2. 确认机制:接收方在成功接收到数据包后,发送确认(ACK)消息给发送方。发送方在收到ACK之前会重传数据包。
  3. 超时重传:发送方在发送数据包后启动一个定时器,如果在指定时间内没有收到ACK,则重传数据包。
  4. 滑动窗口:使用滑动窗口机制来控制发送方和接收方之间的数据流,确保高效的数据传输和流量控制。

示例代码

以下是一个简单的示例,展示如何在UDP的基础上实现保序和可靠传输。这个示例使用Python编写,利用socket库进行UDP通信。

发送方代码
import socket
import threading
import time

# 配置
SERVER_ADDRESS = ('localhost', 12345)
WINDOW_SIZE = 5
TIMEOUT = 2

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)

# 发送数据包
def send_packet(packet, seq_num):
    message = f"{seq_num}:{packet}"
    sock.sendto(message.encode(), SERVER_ADDRESS)
    print(f"Sent: {message}")

# 发送数据
def send_data(data):
    base = 0
    next_seq_num = 0
    window = []

    def ack_listener():
        nonlocal base
        while True:
            try:
                ack, _ = sock.recvfrom(1024)
                ack_num = int(ack.decode())
                print(f"Received ACK: {ack_num}")
                if ack_num >= base:
                    base = ack_num + 1
            except socket.timeout:
                continue

    threading.Thread(target=ack_listener, daemon=True).start()

    while base < len(data):
        while next_seq_num < base + WINDOW_SIZE and next_seq_num < len(data):
            send_packet(data[next_seq_num], next_seq_num)
            window.append((data[next_seq_num], next_seq_num))
            next_seq_num += 1

        time.sleep(TIMEOUT)
        for packet, seq_num in window:
            if seq_num >= base:
                send_packet(packet, seq_num)

# 示例数据
data = ["packet1", "packet2", "packet3", "packet4", "packet5", "packet6", "packet7"]
send_data(data)
接收方代码
import socket

# 配置
SERVER_ADDRESS = ('localhost', 12345)
BUFFER_SIZE = 1024

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(SERVER_ADDRESS)

# 接收数据
def receive_data():
    expected_seq_num = 0
    received_data = []

    while True:
        packet, client_address = sock.recvfrom(BUFFER_SIZE)
        message = packet.decode()
        seq_num, data = message.split(':', 1)
        seq_num = int(seq_num)

        if seq_num == expected_seq_num:
            print(f"Received: {message}")
            received_data.append(data)
            expected_seq_num += 1
            ack_message = str(seq_num)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK: {ack_message}")
        else:
            print(f"Out of order packet: {message}")

# 开始接收数据
receive_data()

解释

  1. 发送方

    • 使用一个滑动窗口来控制数据包的发送。
    • 每个数据包都带有一个序列号。
    • 发送方在发送数据包后等待ACK,如果在超时时间内没有收到ACK,则重传数据包。
    • 使用一个单独的线程来监听ACK消息。
  2. 接收方

    • 接收方按序接收数据包,并发送ACK消息。
    • 如果接收到的包的序列号与期望的序列号一致,则处理该包并发送ACK。
    • 如果接收到的包的序列号不一致,则忽略该包。

总结

在UDP的基础上实现保序和可靠传输需要额外的机制来处理数据包的顺序和确认。通过使用序列号、确认机制、超时重传和滑动窗口,可以有效地实现这些功能。以下是对上述示例代码的总结和进一步的优化建议。

发送方的关键点
  1. 序列号:每个数据包都带有一个唯一的序列号,以便接收方能够按序重组数据包。
  2. 滑动窗口:使用滑动窗口来控制发送的数据包数量,确保不会发送过多的数据包导致网络拥塞。
  3. 超时重传:发送方在发送数据包后启动一个定时器,如果在指定时间内没有收到ACK,则重传数据包。
  4. ACK监听:使用一个单独的线程来监听ACK消息,更新滑动窗口的起始位置。
接收方的关键点
  1. 按序接收:接收方按序接收数据包,并发送ACK消息。如果接收到的包的序列号与期望的序列号一致,则处理该包并发送ACK。
  2. 忽略乱序包:如果接收到的包的序列号不一致,则忽略该包,等待正确的包到达。

进一步优化建议

  1. 丢包检测:在接收方可以实现丢包检测机制,如果检测到丢包,可以请求发送方重传特定的包。
  2. 拥塞控制:实现拥塞控制算法(如TCP中的慢启动和拥塞避免)来动态调整滑动窗口的大小,避免网络拥塞。
  3. 数据校验:在数据包中添加校验和(如CRC)来检测数据包的完整性,确保数据没有在传输过程中被篡改。
  4. 多线程优化:在发送方和接收方都可以使用多线程来提高并发处理能力,减少延迟。

完整示例代码

以下是对上述示例代码的进一步优化和完善。

发送方代码
import socket
import threading
import time

# 配置
SERVER_ADDRESS = ('localhost', 12345)
WINDOW_SIZE = 5
TIMEOUT = 2

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)

# 发送数据包
def send_packet(packet, seq_num):
    message = f"{seq_num}:{packet}"
    sock.sendto(message.encode(), SERVER_ADDRESS)
    print(f"Sent: {message}")

# 发送数据
def send_data(data):
    base = 0
    next_seq_num = 0
    window = []

    def ack_listener():
        nonlocal base
        while True:
            try:
                ack, _ = sock.recvfrom(1024)
                ack_num = int(ack.decode())
                print(f"Received ACK: {ack_num}")
                if ack_num >= base:
                    base = ack_num + 1
            except socket.timeout:
                continue

    threading.Thread(target=ack_listener, daemon=True).start()

    while base < len(data):
        while next_seq_num < base + WINDOW_SIZE and next_seq_num < len(data):
            send_packet(data[next_seq_num], next_seq_num)
            window.append((data[next_seq_num], next_seq_num))
            next_seq_num += 1

        time.sleep(TIMEOUT)
        for packet, seq_num in window:
            if seq_num >= base:
                send_packet(packet, seq_num)

# 示例数据
data = ["packet1", "packet2", "packet3", "packet4", "packet5", "packet6", "packet7"]
send_data(data)
接收方代码
import socket

# 配置
SERVER_ADDRESS = ('localhost', 12345)
BUFFER_SIZE = 1024

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(SERVER_ADDRESS)

# 接收数据
def receive_data():
    expected_seq_num = 0
    received_data = []

    while True:
        packet, client_address = sock.recvfrom(BUFFER_SIZE)
        message = packet.decode()
        seq_num, data = message.split(':', 1)
        seq_num = int(seq_num)

        if seq_num == expected_seq_num:
            print(f"Received: {message}")
            received_data.append(data)
            expected_seq_num += 1
            ack_message = str(seq_num)
            sock.sendto(ack_message.encode(),
            ```python
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK: {ack_message}")
        else:
            print(f"Out of order packet: {message}")

# 开始接收数据
receive_data()

进一步优化和扩展

为了使这个实现更加健壮和高效,可以考虑以下进一步的优化和扩展:

  1. 丢包检测和重传请求

    • 接收方可以检测到丢失的包,并向发送方请求重传特定的包。
    • 发送方可以维护一个重传队列,优先重传丢失的包。
  2. 拥塞控制

    • 实现类似于TCP的拥塞控制算法,如慢启动、拥塞避免、快速重传和快速恢复。
    • 动态调整滑动窗口的大小,以适应网络状况。
  3. 数据校验

    • 在数据包中添加校验和(如CRC)来检测数据包的完整性,确保数据没有在传输过程中被篡改。
    • 接收方在检测到数据包损坏时,可以请求发送方重传该包。
  4. 多线程优化

    • 在发送方和接收方都可以使用多线程来提高并发处理能力,减少延迟。
    • 例如,发送方可以使用多个线程来处理不同的数据包,接收方可以使用多个线程来处理不同的ACK消息。
  5. 流量控制

    • 实现流量控制机制,防止发送方发送过多的数据包导致接收方处理不过来。
    • 可以使用滑动窗口和ACK消息来实现流量控制。

完整示例代码(优化版)

以下是对上述示例代码的进一步优化和扩展,增加了丢包检测和重传请求功能。

发送方代码(优化版)
import socket
import threading
import time

# 配置
SERVER_ADDRESS = ('localhost', 12345)
WINDOW_SIZE = 5
TIMEOUT = 2

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)

# 发送数据包
def send_packet(packet, seq_num):
    message = f"{seq_num}:{packet}"
    sock.sendto(message.encode(), SERVER_ADDRESS)
    print(f"Sent: {message}")

# 发送数据
def send_data(data):
    base = 0
    next_seq_num = 0
    window = []
    acked = set()

    def ack_listener():
        nonlocal base
        while True:
            try:
                ack, _ = sock.recvfrom(1024)
                ack_num = int(ack.decode())
                print(f"Received ACK: {ack_num}")
                if ack_num >= base:
                    base = ack_num + 1
                    acked.add(ack_num)
            except socket.timeout:
                continue

    threading.Thread(target=ack_listener, daemon=True).start()

    while base < len(data):
        while next_seq_num < base + WINDOW_SIZE and next_seq_num < len(data):
            send_packet(data[next_seq_num], next_seq_num)
            window.append((data[next_seq_num], next_seq_num))
            next_seq_num += 1

        time.sleep(TIMEOUT)
        for packet, seq_num in window:
            if seq_num >= base and seq_num not in acked:
                send_packet(packet, seq_num)

# 示例数据
data = ["packet1", "packet2", "packet3", "packet4", "packet5", "packet6", "packet7"]
send_data(data)
接收方代码(优化版)
import socket

# 配置
SERVER_ADDRESS = ('localhost', 12345)
BUFFER_SIZE = 1024

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(SERVER_ADDRESS)

# 接收数据
def receive_data():
    expected_seq_num = 0
    received_data = []

    while True:
        packet, client_address = sock.recvfrom(BUFFER_SIZE)
        message = packet.decode()
        seq_num, data = message.split(':', 1)
        seq_num = int(seq_num)

        if seq_num == expected_seq_num:
            print(f"Received: {message}")
            received_data.append(data)
            expected_seq_num += 1
            ack_message = str(seq_num)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK: {ack_message}")
        else:
            print(f"Out of order packet: {message}")
        ```python
            # 发送ACK以通知发送方当前期望的序列号
            ack_message = str(expected_seq_num - 1)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK for expected seq_num: {ack_message}")

# 开始接收数据
receive_data()

进一步优化和扩展

为了使这个实现更加健壮和高效,可以考虑以下进一步的优化和扩展:

  1. 丢包检测和重传请求

    • 接收方可以检测到丢失的包,并向发送方请求重传特定的包。
    • 发送方可以维护一个重传队列,优先重传丢失的包。
  2. 拥塞控制

    • 实现类似于TCP的拥塞控制算法,如慢启动、拥塞避免、快速重传和快速恢复。
    • 动态调整滑动窗口的大小,以适应网络状况。
  3. 数据校验

    • 在数据包中添加校验和(如CRC)来检测数据包的完整性,确保数据没有在传输过程中被篡改。
    • 接收方在检测到数据包损坏时,可以请求发送方重传该包。
  4. 多线程优化

    • 在发送方和接收方都可以使用多线程来提高并发处理能力,减少延迟。
    • 例如,发送方可以使用多个线程来处理不同的数据包,接收方可以使用多个线程来处理不同的ACK消息。
  5. 流量控制

    • 实现流量控制机制,防止发送方发送过多的数据包导致接收方处理不过来。
    • 可以使用滑动窗口和ACK消息来实现流量控制。

完整示例代码(优化版)

以下是对上述示例代码的进一步优化和扩展,增加了丢包检测和重传请求功能。

发送方代码(优化版)
import socket
import threading
import time

# 配置
SERVER_ADDRESS = ('localhost', 12345)
WINDOW_SIZE = 5
TIMEOUT = 2

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)

# 发送数据包
def send_packet(packet, seq_num):
    message = f"{seq_num}:{packet}"
    sock.sendto(message.encode(), SERVER_ADDRESS)
    print(f"Sent: {message}")

# 发送数据
def send_data(data):
    base = 0
    next_seq_num = 0
    window = []
    acked = set()

    def ack_listener():
        nonlocal base
        while True:
            try:
                ack, _ = sock.recvfrom(1024)
                ack_num = int(ack.decode())
                print(f"Received ACK: {ack_num}")
                if ack_num >= base:
                    base = ack_num + 1
                    acked.add(ack_num)
            except socket.timeout:
                continue

    threading.Thread(target=ack_listener, daemon=True).start()

    while base < len(data):
        while next_seq_num < base + WINDOW_SIZE and next_seq_num < len(data):
            send_packet(data[next_seq_num], next_seq_num)
            window.append((data[next_seq_num], next_seq_num))
            next_seq_num += 1

        time.sleep(TIMEOUT)
        for packet, seq_num in window:
            if seq_num >= base and seq_num not in acked:
                send_packet(packet, seq_num)

# 示例数据
data = ["packet1", "packet2", "packet3", "packet4", "packet5", "packet6", "packet7"]
send_data(data)
接收方代码(优化版)
import socket

# 配置
SERVER_ADDRESS = ('localhost', 12345)
BUFFER_SIZE = 1024

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(SERVER_ADDRESS)

# 接收数据
def receive_data():
    expected_seq_num = 0
    received_data = []

    while True:
        packet, client_address = sock.recvfrom(BUFFER_SIZE)
        message = packet.decode()
        seq_num, data = message.split(':', 1)
        seq_num = int(seq_num)

        if seq_num == expected_seq_num:
            print(f"Received: {message}")
            received_data.append(data)
            expected_seq_num += 1
            ack_message = str(seq_num)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK: {ack_message}else:
            print(f"Out of order packet: {message}")
            # 发送ACK以通知发送方当前期望的序列号
            ack_message = str(expected_seq_num - 1)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK for expected seq_num: {ack_message}")

# 开始接收数据
receive_data()

## RUDP协议
可靠用户数据报协议(Reliable User Datagram Protocol,RUDP)是一种在不可靠的UDP协议之上实现可靠传输的协议。RUDP通过添加确认(ACK)、重传、超时和流量控制等机制,确保数据包的可靠传输。

下面是一个简单的RUDP协议的实现示例,包括发送方和接收方的代码。这个示例实现了基本的可靠传输功能,包括数据包的发送、接收、确认和重传。

### 发送方代码

```python
import socket
import threading
import time

# 配置
SERVER_ADDRESS = ('localhost', 12345)
WINDOW_SIZE = 5
TIMEOUT = 2

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)

# 发送数据包
def send_packet(packet, seq_num):
    message = f"{seq_num}:{packet}"
    sock.sendto(message.encode(), SERVER_ADDRESS)
    print(f"Sent: {message}")

# 发送数据
def send_data(data):
    base = 0
    next_seq_num = 0
    window = []
    acked = set()

    def ack_listener():
        nonlocal base
        while True:
            try:
                ack, _ = sock.recvfrom(1024)
                ack_num = int(ack.decode())
                print(f"Received ACK: {ack_num}")
                if ack_num >= base:
                    base = ack_num + 1
                    acked.add(ack_num)
            except socket.timeout:
                continue

    threading.Thread(target=ack_listener, daemon=True).start()

    while base < len(data):
        while next_seq_num < base + WINDOW_SIZE and next_seq_num < len(data):
            send_packet(data[next_seq_num], next_seq_num)
            window.append((data[next_seq_num], next_seq_num))
            next_seq_num += 1

        time.sleep(TIMEOUT)
        for packet, seq_num in window:
            if seq_num >= base and seq_num not in acked:
                send_packet(packet, seq_num)

# 示例数据
data = ["packet1", "packet2", "packet3", "packet4", "packet5", "packet6", "packet7"]
send_data(data)

接收方代码

import socket

# 配置
SERVER_ADDRESS = ('localhost', 12345)
BUFFER_SIZE = 1024

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(SERVER_ADDRESS)

# 接收数据
def receive_data():
    expected_seq_num = 0
    received_data = []

    while True:
        packet, client_address = sock.recvfrom(BUFFER_SIZE)
        message = packet.decode()
        seq_num, data = message.split(':', 1)
        seq_num = int(seq_num)

        if seq_num == expected_seq_num:
            print(f"Received: {message}")
            received_data.append(data)
            expected_seq_num += 1
            ack_message = str(seq_num)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK: {ack_message}")
        else:
            print(f"Out of order packet: {message}")
            # 发送ACK以通知发送方当前期望的序列号
            ack_message = str(expected_seq_num - 1)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK for expected seq_num: {ack_message}")

# 开始接收数据
receive_data()

进一步优化和扩展

为了使这个实现更加健壮和高效,可以考虑以下进一步的优化和扩展:

  1. 丢包检测和重传请求

    • 接收方可以检测到丢失的包,并向发送方请求重传特定的包。
    • 发送方可以维护一个重传队列,优先重传丢失的包。
  2. 拥塞控制

    • 实现类似于TCP的拥塞控制算法,如慢启动、拥塞避免、快速重传和快速恢复。
    • 动态调整滑动窗口的大小,以适应网络状况。
  3. 数据校验

    • 在数据包中添加校验和(如CRC)来检测数据包的完整性,确保数据没有在传输过程中被篡改。
    • 接收方在检测到数据包损坏时,可以请求发送方重传该包。
  4. 多线程优化

    • 在发送方和接收方都可以使用多线程来提高并发处理能力,减少延迟。
      好的,接下来我们继续优化和扩展RUDP协议的实现,增加更多的功能和改进。

发送方代码(优化版)

在这个版本中,我们将添加以下功能:

  • 丢包检测和重传请求
  • 数据校验(使用简单的校验和)
  • 拥塞控制(简单的滑动窗口调整)
import socket
import threading
import time
import hashlib

# 配置
SERVER_ADDRESS = ('localhost', 12345)
WINDOW_SIZE = 5
TIMEOUT = 2

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)

# 计算校验和
def calculate_checksum(data):
    return hashlib.md5(data.encode()).hexdigest()

# 发送数据包
def send_packet(packet, seq_num):
    checksum = calculate_checksum(packet)
    message = f"{seq_num}:{packet}:{checksum}"
    sock.sendto(message.encode(), SERVER_ADDRESS)
    print(f"Sent: {message}")

# 发送数据
def send_data(data):
    base = 0
    next_seq_num = 0
    window = []
    acked = set()

    def ack_listener():
        nonlocal base
        while True:
            try:
                ack, _ = sock.recvfrom(1024)
                ack_num = int(ack.decode())
                print(f"Received ACK: {ack_num}")
                if ack_num >= base:
                    base = ack_num + 1
                    acked.add(ack_num)
            except socket.timeout:
                continue

    threading.Thread(target=ack_listener, daemon=True).start()

    while base < len(data):
        while next_seq_num < base + WINDOW_SIZE and next_seq_num < len(data):
            send_packet(data[next_seq_num], next_seq_num)
            window.append((data[next_seq_num], next_seq_num))
            next_seq_num += 1

        time.sleep(TIMEOUT)
        for packet, seq_num in window:
            if seq_num >= base and seq_num not in acked:
                send_packet(packet, seq_num)

# 示例数据
data = ["packet1", "packet2", "packet3", "packet4", "packet5", "packet6", "packet7"]
send_data(data)

接收方代码(优化版)

在这个版本中,我们将添加以下功能:

  • 数据校验(使用简单的校验和)
  • 丢包检测和重传请求
import socket
import hashlib

# 配置
SERVER_ADDRESS = ('localhost', 12345)
BUFFER_SIZE = 1024

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(SERVER_ADDRESS)

# 计算校验和
def calculate_checksum(data):
    return hashlib.md5(data.encode()).hexdigest()

# 接收数据
def receive_data():
    expected_seq_num = 0
    received_data = []

    while True:
        packet, client_address = sock.recvfrom(BUFFER_SIZE)
        message = packet.decode()
        seq_num, data, checksum = message.split(':', 2)
        seq_num = int(seq_num)

        # 校验数据包
        if calculate_checksum(data) != checksum:
            print(f"Corrupted packet: {message}")
            continue

        if seq_num == expected_seq_num:
            print(f"Received: {message}")
            received_data.append(data)
            expected_seq_num += 1
            ack_message = str(seq_num)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK: {ack_message}")
        else:
            print(f"Out of order packet: {message}")
            # 发送ACK以通知发送方当前期望的序列号
            ack_message = str(expected_seq_num - 1)
            sock.sendto(ack_message.encode(), client_address)
            print(f"Sent ACK for expected seq_num: {ack_message}")

# 开始接收数据
receive_data()

进一步优化和扩展

为了使这个实现更加健壮和高效,可以考虑以下进一步的优化和扩展:

  1. 拥塞控制

    • 实现类似于TCP的拥塞控制算法,如慢启动、拥塞避免、快速重传和快速恢复。
    • 动态调整滑动窗口的大小,以适应网络状况。
  2. 多线程优化

    • 在发送方和接收方都可以使用多线程来提高并发处理能力,减少延迟。
    • 例如,发送方可以使用多个线程来处理不同的数据包,接收方可以使用多个线程来处理不同的ACK消息。

好的,接下来我们继续优化和扩展RUDP协议的实现,增加更多的功能和改进。

发送方代码(进一步优化版)

在这个版本中,我们将添加以下功能:

  • 拥塞控制(简单的滑动窗口调整)
  • 多线程优化
import socket
import threading
import time
import hashlib

# 配置
SERVER_ADDRESS = ('localhost', 12345)
INITIAL_WINDOW_SIZE = 5
TIMEOUT = 2

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(TIMEOUT)

# 计算校验和
def calculate_checksum(data):
    return hashlib.md5(data.encode()).hexdigest()

# 发送数据包
def send_packet(packet, seq_num):
    checksum = calculate_checksum(packet)
    message = f"{seq_num}:{packet}:{checksum}"
    sock.sendto(message.encode(), SERVER_ADDRESS)
    print(f"Sent: {message}")

# 发送数据
def send_data(data):
    base = 0
    next_seq_num = 0
    window_size = INITIAL_WINDOW_SIZE
    window = []
    acked = set()
    lock = threading.Lock()

    def ack_listener():
        nonlocal base, window_size
        while True:
            try:
                ack, _ = sock.recvfrom(1024)
                ack_num = int(ack.decode())
                print(f"Received ACK: {ack_num}")
                with lock:
                    if ack_num >= base:
                        base = ack_num + 1
                        acked.add(ack_num)
                        # 拥塞控制:增加窗口大小
                        window_size = min(window_size + 1, len(data))
            except socket.timeout:
                continue

    threading.Thread(target=ack_listener, daemon=True).start()

    while base < len(data):
        with lock:
            while next_seq_num < base + window_size and next_seq_num < len(data):
                send_packet(data[next_seq_num], next_seq_num)
                window.append((data[next_seq_num], next_seq_num))
                next_seq_num += 1

        time.sleep(TIMEOUT)
        with lock:
            for packet, seq_num in window:
                if seq_num >= base and seq_num not in acked:
                    send_packet(packet, seq_num)
            # 拥塞控制:减少窗口大小
            window_size = max(1, window_size // 2)

# 示例数据
data = ["packet1", "packet2", "packet3", "packet4", "packet5", "packet6", "packet7"]
send_data(data)

接收方代码(进一步优化版)

在这个版本中,我们将添加以下功能:

  • 多线程优化
import socket
import hashlib
import threading

# 配置
SERVER_ADDRESS = ('localhost', 12345)
BUFFER_SIZE = 1024

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(SERVER_ADDRESS)

# 计算校验和
def calculate_checksum(data):
    return hashlib.md5(data.encode()).hexdigest()

# 接收数据
def receive_data():
    expected_seq_num = 0
    received_data = []
    lock = threading.Lock()

    def handle_packet(packet, client_address):
        nonlocal expected_seq_num
        message = packet.decode()
        seq_num, data, checksum = message.split(':', 2)
        seq_num = int(seq_num)

        # 校验数据包
        if calculate_checksum(data) != checksum:
            print(f"Corrupted packet: {message}")
            return

        with lock:
            if seq_num == expected_seq_num:
                print(f"Received: {message}")
                received_data.append(data)
                expected_seq_num += 1
                ack_message = str(seq_num)
                sock.sendto(ack_message.encode(), client_address)
                print(f"Sent ACK: {ack_message}")
            else:
                print(f"Out of order packet: {message}")
                # 发送ACK以通知发送方当前期望的序列号
                ack_message = str(expected_seq_num - 1)
                sock.sendto(ack_message.encode(), client_address)
                print(f"Sent ACK for expected seq_num: {ack_message}")

    while True:
        packet, client_address = sock.recvfrom(BUFFER_SIZE)
        threading.Thread(target=handle_packet, args=(packet, client_address)).start()

# 开始接收数据
receive_data()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值