Repair project layout and fix Lab024B spectrum detection

This commit is contained in:
LittleSam129
2026-07-21 13:51:41 +03:00
parent acf7a76546
commit 1ff04b12b9
108 changed files with 8270 additions and 8221 deletions

View 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Проверка пройдена: "
"все сообщения учтены."
)