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