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).
- Если буфер переотправки переполнен (размер неотправленных данных $\ge$
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, руководствуйтесь следующими правилами:
- Не реализуйте логику повторного подключения (reconnect) на уровне приложения.
Если произошел сбой сети, не нужно заново создавать экземпляр
PTCPClientи повторно вызыватьconnect(). Библиотека сама переведет сокет в состояниеDISCONNECTED_WAITINGи восстановит физическое TCP-соединение в фоновом режиме. Прикладные вызовыsend()иrecv()просто подождут завершения этого процесса. - Определяйте закрытие сокета по пустому результату чтения.
Единственный верный способ узнать, что удаленная сторона закрыла логический сокет — это получить
b''в качестве результата вызоваawait session.recv(). - Используйте конкурентные задачи для работы с сервером.
Метод
PTCPServer.accept()вызывается в бесконечном цикле, и каждую полученную сессию необходимо передавать в отдельную корутину с помощьюasyncio.create_task(), чтобы сервер мог продолжать принимать новые соединения. - Следите за закрытием ресурсов.
Всегда закрывайте сессию с помощью
await session.close()в блокеfinallyобработчика соединений для предотвращения утечки дескрипторов файлов ОС.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d3c7c3ee8cb77dbc4b6af731c505ce427e436d1b0eaa23bc9c2f7980a4dfd9f
|
|
| MD5 |
cee0aa34fd8767391db32b3487db1e93
|
|
| BLAKE2b-256 |
3ef67578a34002d342d6d4a4484ca598470d3bcede629fb509525810f679a5f7
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d6a33636f29f2bb734446c4290d64be7b4ce5b05aa05b73892622e3b69e16be
|
|
| MD5 |
aec605b1c92af774edd81ef1385286bc
|
|
| BLAKE2b-256 |
17e28ba1631f7b1f1794dbfc6ef8a407e3829b4041454a2fdc38c9ce746da555
|