254 lines
6.5 KiB
Python
254 lines
6.5 KiB
Python
"""
|
||
Lab005. Передача пакетов через виртуальный радиоканал.
|
||
|
||
Эксперимент:
|
||
1. Формируем 100 цифровых пакетов.
|
||
2. Передаём их через виртуальный канал.
|
||
3. Канал может:
|
||
- полностью потерять пакет;
|
||
- изменить отдельные биты.
|
||
4. Приёмник проверяет структуру пакета и CRC-32.
|
||
5. Выводится статистика доставки.
|
||
"""
|
||
|
||
import random
|
||
|
||
from protocol.packet import (
|
||
CRCError,
|
||
MESSAGE_TYPE_TEXT,
|
||
PacketError,
|
||
build_packet,
|
||
parse_packet,
|
||
)
|
||
|
||
from tools.virtual_channel import transmit
|
||
|
||
|
||
# ============================================================
|
||
# Настройки эксперимента
|
||
# ============================================================
|
||
|
||
# Количество передаваемых пакетов.
|
||
PACKET_COUNT = 100
|
||
|
||
# Вероятность полной потери одного пакета.
|
||
#
|
||
# 0.10 означает 10 %.
|
||
DROP_PROBABILITY = 0.10
|
||
|
||
# Вероятность повреждения каждого отдельного бита.
|
||
#
|
||
# 0.002 означает:
|
||
# 0,2 % вероятности ошибки для каждого бита.
|
||
BIT_ERROR_PROBABILITY = 0.002
|
||
|
||
# Генератор случайных чисел.
|
||
#
|
||
# Число 2026 позволяет получать одинаковый результат
|
||
# при каждом запуске программы.
|
||
random_generator = random.Random(2026)
|
||
|
||
|
||
# ============================================================
|
||
# Счётчики результатов
|
||
# ============================================================
|
||
|
||
sent_packets = 0
|
||
|
||
# Пакеты, полностью исчезнувшие в канале.
|
||
dropped_packets = 0
|
||
|
||
# Доставленные, но повреждённые пакеты.
|
||
rejected_packets = 0
|
||
|
||
# Пакеты, правильно принятые и разобранные.
|
||
received_ok = 0
|
||
|
||
# Общее количество изменённых битов.
|
||
total_flipped_bits = 0
|
||
|
||
|
||
# ============================================================
|
||
# Передача серии пакетов
|
||
# ============================================================
|
||
|
||
for sequence_number in range(PACKET_COUNT):
|
||
|
||
# Создаём уникальное сообщение для каждого пакета.
|
||
message = f"ПАКЕТ {sequence_number}"
|
||
|
||
# Текст превращается в байты UTF-8.
|
||
payload = message.encode("utf-8")
|
||
|
||
# Формируем полный пакет с заголовком и CRC-32.
|
||
packet = build_packet(
|
||
payload=payload,
|
||
message_type=MESSAGE_TYPE_TEXT,
|
||
sequence_number=sequence_number,
|
||
)
|
||
|
||
sent_packets += 1
|
||
|
||
# Передаём пакет через виртуальный канал.
|
||
received_packet, flipped_bits = transmit(
|
||
packet=packet,
|
||
drop_probability=DROP_PROBABILITY,
|
||
bit_error_probability=BIT_ERROR_PROBABILITY,
|
||
random_generator=random_generator,
|
||
)
|
||
|
||
total_flipped_bits += flipped_bits
|
||
|
||
# None означает, что пакет полностью потерян.
|
||
if received_packet is None:
|
||
dropped_packets += 1
|
||
continue
|
||
|
||
# Пытаемся разобрать принятый пакет.
|
||
try:
|
||
parsed_packet = parse_packet(received_packet)
|
||
|
||
except (CRCError, PacketError):
|
||
# CRCError:
|
||
# контрольная сумма не совпала.
|
||
#
|
||
# PacketError:
|
||
# повреждены SYNC, версия, длина
|
||
# или другая часть структуры.
|
||
rejected_packets += 1
|
||
continue
|
||
|
||
# Восстанавливаем текст из полезной нагрузки.
|
||
restored_message = parsed_packet.payload.decode("utf-8")
|
||
|
||
# Проверяем, что получен именно тот пакет,
|
||
# который был передан.
|
||
assert parsed_packet.sequence_number == sequence_number
|
||
assert restored_message == message
|
||
|
||
received_ok += 1
|
||
|
||
|
||
# ============================================================
|
||
# Вывод настроек
|
||
# ============================================================
|
||
|
||
print("=== Lab005. Виртуальный канал ===")
|
||
|
||
print("\nНастройки эксперимента:")
|
||
|
||
print(
|
||
"Количество пакетов:",
|
||
PACKET_COUNT,
|
||
)
|
||
|
||
print(
|
||
"Вероятность полной потери пакета:",
|
||
DROP_PROBABILITY,
|
||
)
|
||
|
||
print(
|
||
"Вероятность ошибки отдельного бита:",
|
||
BIT_ERROR_PROBABILITY,
|
||
)
|
||
|
||
|
||
# ============================================================
|
||
# Вывод результатов
|
||
# ============================================================
|
||
|
||
print("\nРезультаты:")
|
||
|
||
print(
|
||
"Передано пакетов:",
|
||
sent_packets,
|
||
)
|
||
|
||
print(
|
||
"Потеряно полностью:",
|
||
dropped_packets,
|
||
)
|
||
|
||
print(
|
||
"Отклонено из-за повреждений:",
|
||
rejected_packets,
|
||
)
|
||
|
||
print(
|
||
"Принято правильно:",
|
||
received_ok,
|
||
)
|
||
|
||
print(
|
||
"Всего изменено битов:",
|
||
total_flipped_bits,
|
||
)
|
||
|
||
|
||
# ============================================================
|
||
# Расчёт процентов
|
||
# ============================================================
|
||
|
||
delivery_rate = (
|
||
received_ok
|
||
/ sent_packets
|
||
* 100
|
||
)
|
||
|
||
drop_rate = (
|
||
dropped_packets
|
||
/ sent_packets
|
||
* 100
|
||
)
|
||
|
||
rejection_rate = (
|
||
rejected_packets
|
||
/ sent_packets
|
||
* 100
|
||
)
|
||
|
||
packet_failure_rate = (
|
||
dropped_packets
|
||
+ rejected_packets
|
||
) / sent_packets * 100
|
||
|
||
|
||
print("\nСтатистика:")
|
||
|
||
print(
|
||
f"Успешно доставлено: "
|
||
f"{delivery_rate:.1f} %"
|
||
)
|
||
|
||
print(
|
||
f"Потеряно полностью: "
|
||
f"{drop_rate:.1f} %"
|
||
)
|
||
|
||
print(
|
||
f"Отклонено приёмником: "
|
||
f"{rejection_rate:.1f} %"
|
||
)
|
||
|
||
print(
|
||
f"Общая доля недоставленных пакетов: "
|
||
f"{packet_failure_rate:.1f} %"
|
||
)
|
||
|
||
|
||
# ============================================================
|
||
# Контроль правильности
|
||
# ============================================================
|
||
|
||
accounted_packets = (
|
||
received_ok
|
||
+ dropped_packets
|
||
+ rejected_packets
|
||
)
|
||
|
||
assert accounted_packets == sent_packets
|
||
|
||
print(
|
||
"\nПроверка пройдена: "
|
||
"все переданные пакеты учтены."
|
||
) |