Skip to main content

Persistent TCP (PTCP) session-layer protocol implementation over asyncio

Project description


aioptcp — Python-реализация протокола APTCP

Библиотека aioptcp — это асинхронная реализация сеансового протокола APTCP (работающего поверх стандартного транспортного протокола TCP) для среды asyncio.

Протокол APTCP разработан для обеспечения непрерывности логического соединения при кратковременных обрывах сети, переключениях между интерфейсами (Wi-Fi/LTE) или смене IP-адресов.

Важно по терминологии:

  • Сам сетевой протокол называется APTCP.
  • Реализующая его библиотека для Python называется aioptcp (префикс aio означает использование asyncio).
  • Внутри кода библиотеки классы используют префикс PTCP (например, PTCPSocket, PTCPClient, PTCPServer), так как указание на асинхронность уже вынесено в название самого пакета.

Архитектура и особенности

  • Прозрачность для прикладного кода: При падении физического TCP-соединения логический сокет переходит в режим ожидания. Данные буферизируются на отправку, а вызовы методов send() и recv() блокируются, но не вызывают ошибок. После восстановления канала сессия APTCP автоматически возобновляется без потерь данных.
  • Встроенный контроль переполнения (Backpressure): Ограничение буфера переотправки предотвращает бесконтрольное потребление оперативной памяти. Метод send() автоматически приостанавливает выполнение корутины, если лимит буфера превышен.
  • Безопасность возобновления сессий: Возобновление сессии APTCP авторизуется с помощью подписи HMAC-SHA256 на базе ключа, сгенерированного в процессе первичного обмена по алгоритму Диффи-Хеллмана (2048-bit MODP Group).

Установка

Поместите пакет aioptcp в директорию вашего проекта или установите его:

pip install aioptcp

Руководство по использованию (Quick Start)

1. Запуск APTCP-сервера

Сервер слушает входящие TCP-подключения, обрабатывает рукопожатия APTCP и предоставляет приложению готовые логические сессии.

import asyncio
from aioptcp import PTCPServer, PTCPSocket

async def handle_client(session: PTCPSocket):
    session_hex = session.session_id.hex()
    print(f"[Сервер] APTCP-сессия {session_hex} успешно установлена.")
    
    try:
        while True:
            # Чтение данных из логического сокета APTCP
            data = await session.recv(1024)
            if not data:
                # Получен пустой байтовый массив — клиент закрыл соединение штатно (EOF)
                print(f"[Сервер] Сессия {session_hex} закрыта клиентом.")
                break
                
            print(f"[Сервер] Получено от {session_hex}: {data.decode(errors='ignore')}")
            
            # Отправка эхо-ответа обратно в сессию
            await session.send(b"Echo: " + data)
            
    except Exception as e:
        print(f"[Сервер] Ошибка в сессии {session_hex}: {e}")
    finally:
        # Корректно закрываем ресурсы сокета
        await session.close()

async def main():
    # Запуск сервера APTCP на порту 8888 с таймаутом удержания сессии 30 секунд
    server = PTCPServer(host='127.0.0.1', port=8888, timeout=30)
    await server.start()
    print("[Сервер] APTCP-сервер запущен и ожидает подключений...")
    
    while True:
        # Ожидание нового логического подключения APTCP
        session = await server.accept()
        asyncio.create_task(handle_client(session))

if __name__ == "__main__":
    asyncio.run(main())

2. Запуск APTCP-клиента

Клиент инициирует соединение. В случае физического обрыва связи библиотека переподключается в фоновом режиме, при этом прикладной цикл отправки/приема не прерывается.

import asyncio
from aioptcp import PTCPClient

async def main():
    # Создание клиента APTCP с таймаутом удержания сессии 30 секунд
    client = PTCPClient(host='127.0.0.1', port=8888, timeout=30)
    
    try:
        print("[Клиент] Подключение к APTCP-серверу...")
        await client.connect()
        print(f"[Клиент] Логическое соединение установлено. ID сессии: {client.session_id.hex()}")
        
        # Отправка сообщений в цикле
        for i in range(1, 6):
            message = f"Message {i}".encode()
            print(f"[Клиент] Отправка: {message.decode()}")
            
            # Если сеть пропадет, метод send заблокируется, но не упадет с ошибкой
            await client.send(message)
            
            # Ожидание ответа
            response = await client.recv(1024)
            print(f"[Клиент] Ответ от сервера: {response.decode(errors='ignore')}")
            
            await asyncio.sleep(2)
            
    except Exception as e:
        print(f"[Клиент] Критическая ошибка: {e}")
    finally:
        # Штатное закрытие логического сокета и отправка кадра CLOSE
        print("[Клиент] Закрытие соединения.")
        await client.close()

if __name__ == "__main__":
    asyncio.run(main())

Справочник по API (API Reference)

Класс PTCPSocket

Базовый класс, реализующий логический сокет протокола APTCP. Используется клиентом напрямую (наследуется в PTCPClient) и возвращается методом PTCPServer.accept().

  • state: PTCPState Текущее состояние логического сокета. Значения (IntEnum):
    • PTCPState.CONNECTING (1) — выполняется первичное рукопожатие.
    • PTCPState.ESTABLISHED (2) — соединение установлено, передача разрешена.
    • PTCPState.DISCONNECTED_WAITING (3) — физический канал утерян, ожидание восстановления.
    • PTCPState.RESUMING (4) — выполняется восстановление сессии на новом TCP-канале.
    • PTCPState.CLOSED (5) — соединение закрыто окончательно.
  • session_id: bytes Уникальный 16-байтный идентификатор сессии APTCP. Заполняется после завершения рукопожатия.
  • buffer_size_limit: int Лимит размера буфера переотправки (по умолчанию 5 * 1024 * 1024 байт, или 5 МБ).
  • async send(data: bytes) -> bool Асинхронная отправка данных.
    • Если буфер переотправки переполнен (размер неотправленных данных $\ge$ buffer_size_limit), корутина приостанавливает выполнение (блокируется) до тех пор, пока от противоположной стороны не придет ACK-подтверждение.
    • Если сокет находится в состоянии DISCONNECTED_WAITING или RESUMING, данные буферизируются, а корутина завершается успешно.
    • Возвращает True при успешной буферизации/отправке. Возвращает False, если сокет окончательно закрыт (CLOSED).
  • async recv(size: int) -> bytes Асинхронное чтение данных из прикладного буфера приема.
    • Блокирует выполнение до появления данных в буфере.
    • Возвращает полученные данные длиной не более size байт.
    • Важно: Возвращает пустую строку байт (b''), когда удаленная сторона штатно закрыла соединение (сигнал EOF).
  • async close(send_close_frame: bool = True) Завершает логическую сессию и освобождает системные ресурсы. Если send_close_frame равен True, отправляет удаленной стороне служебный кадр CLOSE.

Класс PTCPClient(PTCPSocket)

Класс клиента протокола APTCP, наследующий логику PTCPSocket.

  • __init__(host: str, port: int, timeout: int = 30) Создает экземпляр клиента. timeout определяет, в течение какого времени (в секундах) клиент будет пытаться восстановить логическую сессию после обрыва сети.
  • async connect() Инициирует физическое соединение с сервером и производит обмен ключами (рукопожатие Диффи-Хеллмана). Блокирует выполнение до перехода сокета в состояние ESTABLISHED. При невозможности установить первичное соединение в течение timeout секунд возбуждает TimeoutError.

Класс PTCPServer

Класс сервера, управляющий жизненным циклом сессий APTCP.

  • __init__(host: str, port: int, timeout: int = 30) Создает экземпляр сервера. timeout — время ожидания переподключения клиента до уничтожения сессии из памяти сервера.
  • async start() Запускает TCP-слушатель на указанном хосте и порту, а также активирует фоновый сборщик мусора (Garbage Collector) для очистки зависших сессий.
  • async accept() -> PTCPSocket Ожидает завершения рукопожатия с новым клиентом и возвращает готовый объект сокета PTCPSocket в состоянии ESTABLISHED.
  • sessions: dict Словарь активных сессий сервера, где ключ — session_id (16 байт), а значение — экземпляр PTCPSocket.

Инструкции для ИИ (AI Integration Guidelines)

При написании программного кода, использующего aioptcp, руководствуйтесь следующими правилами:

  1. Не реализуйте логику повторного подключения (reconnect) на уровне приложения. Если произошел сбой сети, не нужно заново создавать экземпляр PTCPClient и повторно вызывать connect(). Библиотека сама переведет сокет в состояние DISCONNECTED_WAITING и восстановит физическое TCP-соединение в фоновом режиме. Прикладные вызовы send() и recv() просто подождут завершения этого процесса.
  2. Определяйте закрытие сокета по пустому результату чтения. Единственный верный способ узнать, что удаленная сторона закрыла логический сокет — это получить b'' в качестве результата вызова await session.recv().
  3. Используйте конкурентные задачи для работы с сервером. Метод PTCPServer.accept() вызывается в бесконечном цикле, и каждую полученную сессию необходимо передавать в отдельную корутину с помощью asyncio.create_task(), чтобы сервер мог продолжать принимать новые соединения.
  4. Следите за закрытием ресурсов. Всегда закрывайте сессию с помощью await session.close() в блоке finally обработчика соединений для предотвращения утечки дескрипторов файлов ОС.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aioptcp-1.0.0.tar.gz (21.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aioptcp-1.0.0-py3-none-any.whl (17.3 kB view details)

Uploaded Python 3

File details

Details for the file aioptcp-1.0.0.tar.gz.

File metadata

  • Download URL: aioptcp-1.0.0.tar.gz
  • Upload date:
  • Size: 21.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.14

File hashes

Hashes for aioptcp-1.0.0.tar.gz
Algorithm Hash digest
SHA256 8d3c7c3ee8cb77dbc4b6af731c505ce427e436d1b0eaa23bc9c2f7980a4dfd9f
MD5 cee0aa34fd8767391db32b3487db1e93
BLAKE2b-256 3ef67578a34002d342d6d4a4484ca598470d3bcede629fb509525810f679a5f7

See more details on using hashes here.

File details

Details for the file aioptcp-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: aioptcp-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 17.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.14

File hashes

Hashes for aioptcp-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2d6a33636f29f2bb734446c4290d64be7b4ce5b05aa05b73892622e3b69e16be
MD5 aec605b1c92af774edd81ef1385286bc
BLAKE2b-256 17e28ba1631f7b1f1794dbfc6ef8a407e3829b4041454a2fdc38c9ce746da555

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page