Repair project layout and fix Lab024B spectrum detection
This commit is contained in:
325
tests/lab006_stop_and_wait_arq.py
Normal file
325
tests/lab006_stop_and_wait_arq.py
Normal file
@@ -0,0 +1,325 @@
|
||||
"""
|
||||
Lab006. Надёжная передача пакетов методом Stop-and-Wait ARQ.
|
||||
|
||||
Передатчик:
|
||||
1. Отправляет пакет.
|
||||
2. Ожидает подтверждение ACK.
|
||||
3. При отсутствии правильного ACK повторяет передачу.
|
||||
4. После исчерпания попыток считает сообщение недоставленным.
|
||||
|
||||
Приёмник:
|
||||
1. Проверяет пакет.
|
||||
2. Отбрасывает повреждённые пакеты.
|
||||
3. Отправляет ACK для правильного пакета.
|
||||
4. Не передаёт приложению повторные копии одного сообщения.
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
from protocol.packet import (
|
||||
CRCError,
|
||||
MESSAGE_TYPE_ACK,
|
||||
MESSAGE_TYPE_TEXT,
|
||||
PacketError,
|
||||
build_packet,
|
||||
parse_packet,
|
||||
)
|
||||
|
||||
from tools.virtual_channel import transmit
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Настройки эксперимента
|
||||
# ============================================================
|
||||
|
||||
MESSAGE_COUNT = 100
|
||||
|
||||
# Максимальное количество передач одного сообщения.
|
||||
MAX_ATTEMPTS = 5
|
||||
|
||||
# Параметры канала от передатчика к приёмнику.
|
||||
DATA_DROP_PROBABILITY = 0.10
|
||||
DATA_BIT_ERROR_PROBABILITY = 0.002
|
||||
|
||||
# Параметры обратного канала для ACK.
|
||||
ACK_DROP_PROBABILITY = 0.10
|
||||
ACK_BIT_ERROR_PROBABILITY = 0.002
|
||||
|
||||
# Фиксированное число делает эксперимент повторяемым.
|
||||
random_generator = random.Random(2026)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Счётчики
|
||||
# ============================================================
|
||||
|
||||
delivered_messages = 0
|
||||
failed_messages = 0
|
||||
|
||||
data_transmissions = 0
|
||||
ack_transmissions = 0
|
||||
|
||||
duplicate_packets = 0
|
||||
|
||||
invalid_data_packets = 0
|
||||
invalid_ack_packets = 0
|
||||
|
||||
dropped_data_packets = 0
|
||||
dropped_ack_packets = 0
|
||||
|
||||
# Номера пакетов, уже переданных приложению приёмника.
|
||||
received_sequences = set()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Передача сообщений
|
||||
# ============================================================
|
||||
|
||||
for sequence_number in range(MESSAGE_COUNT):
|
||||
|
||||
message = f"ПАКЕТ {sequence_number}"
|
||||
payload = message.encode("utf-8")
|
||||
|
||||
data_packet = build_packet(
|
||||
payload=payload,
|
||||
message_type=MESSAGE_TYPE_TEXT,
|
||||
sequence_number=sequence_number,
|
||||
)
|
||||
|
||||
message_confirmed = False
|
||||
|
||||
# Повторяем передачу до MAX_ATTEMPTS раз.
|
||||
for attempt_number in range(1, MAX_ATTEMPTS + 1):
|
||||
|
||||
data_transmissions += 1
|
||||
|
||||
received_data_packet, _ = transmit(
|
||||
packet=data_packet,
|
||||
drop_probability=DATA_DROP_PROBABILITY,
|
||||
bit_error_probability=DATA_BIT_ERROR_PROBABILITY,
|
||||
random_generator=random_generator,
|
||||
)
|
||||
|
||||
# Пакет полностью потерялся.
|
||||
if received_data_packet is None:
|
||||
dropped_data_packets += 1
|
||||
continue
|
||||
|
||||
# Приёмник проверяет пакет.
|
||||
try:
|
||||
parsed_data = parse_packet(received_data_packet)
|
||||
|
||||
except (CRCError, PacketError):
|
||||
invalid_data_packets += 1
|
||||
continue
|
||||
|
||||
# Проверка типа сообщения.
|
||||
if parsed_data.message_type != MESSAGE_TYPE_TEXT:
|
||||
invalid_data_packets += 1
|
||||
continue
|
||||
|
||||
# Проверяем, не получали ли мы этот пакет ранее.
|
||||
if parsed_data.sequence_number in received_sequences:
|
||||
duplicate_packets += 1
|
||||
|
||||
else:
|
||||
restored_message = parsed_data.payload.decode("utf-8")
|
||||
|
||||
assert restored_message == message
|
||||
|
||||
received_sequences.add(
|
||||
parsed_data.sequence_number
|
||||
)
|
||||
|
||||
# Формируем подтверждение.
|
||||
#
|
||||
# ACK имеет тот же sequence_number,
|
||||
# что и подтверждаемый пакет.
|
||||
ack_packet = build_packet(
|
||||
payload=b"",
|
||||
message_type=MESSAGE_TYPE_ACK,
|
||||
sequence_number=parsed_data.sequence_number,
|
||||
)
|
||||
|
||||
ack_transmissions += 1
|
||||
|
||||
received_ack_packet, _ = transmit(
|
||||
packet=ack_packet,
|
||||
drop_probability=ACK_DROP_PROBABILITY,
|
||||
bit_error_probability=ACK_BIT_ERROR_PROBABILITY,
|
||||
random_generator=random_generator,
|
||||
)
|
||||
|
||||
# ACK полностью потерялся.
|
||||
if received_ack_packet is None:
|
||||
dropped_ack_packets += 1
|
||||
continue
|
||||
|
||||
# Передатчик проверяет ACK.
|
||||
try:
|
||||
parsed_ack = parse_packet(received_ack_packet)
|
||||
|
||||
except (CRCError, PacketError):
|
||||
invalid_ack_packets += 1
|
||||
continue
|
||||
|
||||
# ACK должен иметь правильный тип и номер.
|
||||
if (
|
||||
parsed_ack.message_type != MESSAGE_TYPE_ACK
|
||||
or parsed_ack.sequence_number != sequence_number
|
||||
):
|
||||
invalid_ack_packets += 1
|
||||
continue
|
||||
|
||||
# Подтверждение получено.
|
||||
message_confirmed = True
|
||||
break
|
||||
|
||||
if message_confirmed:
|
||||
delivered_messages += 1
|
||||
else:
|
||||
failed_messages += 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Расчёт статистики
|
||||
# ============================================================
|
||||
|
||||
delivery_rate = (
|
||||
delivered_messages
|
||||
/ MESSAGE_COUNT
|
||||
* 100
|
||||
)
|
||||
|
||||
failure_rate = (
|
||||
failed_messages
|
||||
/ MESSAGE_COUNT
|
||||
* 100
|
||||
)
|
||||
|
||||
average_data_transmissions = (
|
||||
data_transmissions
|
||||
/ MESSAGE_COUNT
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Вывод результата
|
||||
# ============================================================
|
||||
|
||||
print("=== Lab006. Stop-and-Wait ARQ ===")
|
||||
|
||||
print("\nНастройки:")
|
||||
|
||||
print("Количество сообщений:", MESSAGE_COUNT)
|
||||
print("Максимум попыток:", MAX_ATTEMPTS)
|
||||
|
||||
print(
|
||||
"Вероятность потери DATA:",
|
||||
DATA_DROP_PROBABILITY,
|
||||
)
|
||||
|
||||
print(
|
||||
"Вероятность битовой ошибки DATA:",
|
||||
DATA_BIT_ERROR_PROBABILITY,
|
||||
)
|
||||
|
||||
print(
|
||||
"Вероятность потери ACK:",
|
||||
ACK_DROP_PROBABILITY,
|
||||
)
|
||||
|
||||
print(
|
||||
"Вероятность битовой ошибки ACK:",
|
||||
ACK_BIT_ERROR_PROBABILITY,
|
||||
)
|
||||
|
||||
|
||||
print("\nОсновные результаты:")
|
||||
|
||||
print(
|
||||
"Успешно подтверждено сообщений:",
|
||||
delivered_messages,
|
||||
)
|
||||
|
||||
print(
|
||||
"Не подтверждено сообщений:",
|
||||
failed_messages,
|
||||
)
|
||||
|
||||
print(
|
||||
f"Доля успешной доставки: "
|
||||
f"{delivery_rate:.1f} %"
|
||||
)
|
||||
|
||||
print(
|
||||
f"Доля недоставленных сообщений: "
|
||||
f"{failure_rate:.1f} %"
|
||||
)
|
||||
|
||||
|
||||
print("\nПередачи:")
|
||||
|
||||
print(
|
||||
"Всего передач DATA:",
|
||||
data_transmissions,
|
||||
)
|
||||
|
||||
print(
|
||||
"Всего передач ACK:",
|
||||
ack_transmissions,
|
||||
)
|
||||
|
||||
print(
|
||||
f"Среднее число передач DATA "
|
||||
f"на одно сообщение: "
|
||||
f"{average_data_transmissions:.2f}"
|
||||
)
|
||||
|
||||
|
||||
print("\nОшибки канала:")
|
||||
|
||||
print(
|
||||
"Полностью потеряно DATA:",
|
||||
dropped_data_packets,
|
||||
)
|
||||
|
||||
print(
|
||||
"Повреждено DATA:",
|
||||
invalid_data_packets,
|
||||
)
|
||||
|
||||
print(
|
||||
"Полностью потеряно ACK:",
|
||||
dropped_ack_packets,
|
||||
)
|
||||
|
||||
print(
|
||||
"Повреждено ACK:",
|
||||
invalid_ack_packets,
|
||||
)
|
||||
|
||||
print(
|
||||
"Получено повторных DATA-пакетов:",
|
||||
duplicate_packets,
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Автоматические проверки
|
||||
# ============================================================
|
||||
|
||||
assert (
|
||||
delivered_messages
|
||||
+ failed_messages
|
||||
== MESSAGE_COUNT
|
||||
)
|
||||
|
||||
assert delivered_messages <= len(received_sequences)
|
||||
|
||||
assert data_transmissions >= MESSAGE_COUNT
|
||||
|
||||
print(
|
||||
"\nПроверка пройдена: "
|
||||
"все сообщения учтены."
|
||||
)
|
||||
Reference in New Issue
Block a user