Skip to content

lacolle87/TransaqConnectorBridge

Repository files navigation

tcbridge

TCP-обёртка над TRANSAQ XML Connector. Запускает Windows-only DLL txmlconnector64.dll внутри Docker-контейнера через Wine и предоставляет к ней TCP-интерфейс, доступный с любой платформы и любого языка.

Зачем

TRANSAQ Connector это проприетарная Windows DLL от брокера ФИНАМ для алготрейдинга на Московской бирже. DLL общается XML-сообщениями и может быть загружена только в Windows-процесс.

tcbridge оборачивает эту DLL в TCP-сервер:

  • Работает на Linux в Docker-контейнере (через Wine)
  • Подключение с помощью любого языка — Python, Go, Rust, Node.js, C# — всё что умеет работать с TCP-сокетами
  • Поддержка нескольких клиентов одновременно (несколько command + несколько stream)
  • Деплой как самодостаточный Docker-сервис
┌─────────────┐       TCP        ┌─────────────────────────────────────┐
│  Ваше       │◄────────────────►│         tcbridge (Docker/Wine)      │
│  приложение │  command channel │  ┌───────────┐   ┌───────────────┐  │
│  на любом   │◄────────────────►│  │ TCP Server│◄─►│ TXmlConnector │  │
│  языке      │  stream channel  │  └───────────┘   │     DLL       │  │
└─────────────┘                  │                  └───────────────┘  │
                                 └─────────────────────────────────────┘

Быстрый старт

Требования

  • Docker
  • txmlconnector64.dll скачивается с сайта ФИНАМ (в репозиторий не включена)

Запуск

  1. Поместите txmlconnector64.dll в корень проекта.

  2. Настройте config.ini (см. раздел Конфигурация).

  3. Сборка и запуск:

docker build -t tcbridge .
docker run -d --name tcbridge -p 9090:9090 tcbridge

Или через docker compose:

docker compose -f compose.dev.yaml up -d
  1. Подключайтесь к localhost:9090.

Конфигурация

Настройка выполняется через файл config.ini в формате INI. По умолчанию tcbridge ищет config.ini в рабочей директории. Путь можно переопределить через переменную окружения TCBRIDGE_CONFIG:

TCBRIDGE_CONFIG=/path/to/my_config.ini wine tcbridge.exe

Формат

Файл разделён на три секции: [server], [logging] и [timeouts]. Поддерживаются комментарии через # и ;.

Пример config.ini

[server]
dll_path       = txmlconnector64.dll
port           = 9090
buffer_size_kb = 1024

[logging]
path        = .\logs
dll_path    = .\dll_logs
level       = 2
max_size_mb = 2
max_files   = 5
tz_offset   = 3

[timeouts]
cmd_recv_ms           = 5000
stream_send_ms        = 5000
keepalive_time_ms     = 60000
keepalive_interval_ms = 15000
handshake_ms          = 15000

Секция [server]

Параметр По умолчанию Диапазон Описание
dll_path txmlconnector64.dll Путь к DLL внутри контейнера
port 9090 1–65535 TCP-порт для входящих подключений
buffer_size_kb 1024 64–16384 Размер ring buffer для broadcast-сообщений (КБ)

Секция [logging]

Параметр По умолчанию Диапазон Описание
path .\logs Директория для лог-файлов tcbridge
dll_path .\dll_logs Директория для лог-файлов DLL (логи TRANSAQ Connector)
level 2 1–3 Уровень логирования (см. ниже)
max_size_mb 10 1–1024 Максимальный размер лог-файла tcbridge в МБ до ротации
max_files 5 1–100 Количество ротированных лог-файлов tcbridge
tz_offset 3 −12 – +14 Смещение от UTC для меток времени в логах (3 = Москва)

Уровни логирования (параметр level) влияют и на DLL, и на tcbridge:

Уровень DLL (TRANSAQ Connector) tcbridge
1 Команды, результаты, ошибки, предупреждения WARN и ERROR
2 То же + server_status, trades, orders, positions, client INFO и выше
3 Все сообщения, приходящие в callback DEBUG и выше

Секция [timeouts]

Параметр По умолчанию Диапазон (мс) Описание
cmd_recv_ms 5000 100–60000 Таймаут ожидания данных от command-клиента (select timeout)
stream_send_ms 5000 1000–120000 Таймаут отправки данных stream-клиенту (SO_SNDTIMEO)
keepalive_time_ms 60000 1000–600000 Время до первой keepalive-пробы на TCP-сокете
keepalive_interval_ms 15000 1000–60000 Интервал между keepalive-пробами
handshake_ms 15000 1000–60000 Таймаут на получение байта типа канала после подключения

Пояснения к таймаутам:

  • cmd_recv_ms определяет, как часто command-handler проверяет флаг остановки сервера. Это не таймаут на получение всей команды, а интервал select-цикла. При штатной работе клиент может держать соединение сколь угодно долго.
  • stream_send_ms если stream-клиент не успевает принять данные за это время (например, зависший клиент), соединение считается мёртвым и закрывается.
  • keepalive_time_ms / keepalive_interval_ms TCP keepalive помогает обнаружить обрыв сети или crash клиента без корректного закрытия сокета.
  • handshake_ms — защита от подключений, которые открывают TCP-соединение, но не отправляют байт канала (сканеры портов, ошибочные подключения).

Протокол

tcbridge использует простой бинарный протокол поверх TCP.

Типы каналов

При подключении клиент отправляет 1 байт, определяющий тип канала:

Байт Канал Направление Описание
0x01 Command двунаправленный Отправка XML-команд, получение ответов
0x02 Stream сервер → клиент Получение асинхронных callback-сообщений от DLL

Формат фрейма

Каждое сообщение передаётся в виде фрейма с 4-байтным заголовком длины (big-endian):

┌──────────────────────────┬──────────────────────────────┐
│  4 байта (big-endian)    │  N байт (UTF-8)              │
│  длина payload           │  XML-сообщение               │
└──────────────────────────┴──────────────────────────────┘

Максимальный размер фрейма: 16 МБ.

XML-команды

Формат XML-команд и ответов полностью соответствует документации TRANSAQ XML Connector. tcbridge прозрачно передаёт XML между TCP-клиентом и DLL без какой-либо модификации. Подходит любой язык программирования, способный работать с TCP-сокетами и формировать XML.

Документация по XML-командам TRANSAQ доступна на сайте ФИНАМ.

Подключение и отключение

Подключение, открыть TCP-соединение на порт tcbridge и отправить 1 байт типа канала:

1. Открыть TCP-соединение к хосту tcbridge
2. Отправить 1 байт: 0x01 (command) или 0x02 (stream)
3. Соединение установлено — можно обмениваться фреймами

Типичная схема, два соединения: одно для команд, второе для потока данных:

Client                          tcbridge                        DLL
  │                                │                               │
  │── TCP connect ────────────────►│                               │
  │── 0x01 ───────────────────────►│        command channel        │
  │                                │                               │
  │── TCP connect ────────────────►│                               │
  │── 0x02 ───────────────────────►│        stream channel         │
  │                                │                               │
  │── [len][XML command] ─────────►│──── SendCommand(xml) ────────►│
  │                                │◄─── XML response ─────────────│
  │◄── [len][XML response] ─────── │                               │
  │                                │                               │
  │                                │◄─── callback(xml) ────────────│
  │◄── [len][XML message] ──────── │         (stream)              │

Отключение, просто закрыть TCP-соединение:

1. Отправить команду disconnect по command каналу
   (если нужно корректно отключиться от сервера TRANSAQ)
2. Закрыть TCP-сокет command канала
3. Закрыть TCP-сокет stream канала

tcbridge автоматически обнаруживает закрытые соединения и освобождает ресурсы. Принудительный разрыв (crash клиента, потеря сети) тоже обрабатывается корректно - keepalive-пробы определят мёртвое соединение.

Архитектура

src/
├── main.cpp                        — точка входа, загрузка конфигурации, обработка сигналов
├── config/
│   └── config.cpp/h                — парсер INI-файлов и валидация конфигурации
├── init/
│   └── initialization.cpp/h        — оркестрация запуска
├── dll/
│   └── dll_wrapper.cpp/h           — потокобезопасная обёртка над TXmlConnector DLL
├── net/
│   ├── tcp_server.cpp/h            — TCP-сервер: lifecycle, helpers
│   ├── tcp_server_io.cpp           — IO-поток: accept, чтение команд, отправка ответов
│   ├── tcp_server_broadcast.cpp    — broadcast-поток и DLL-поток
│   ├── ring_buffer.cpp/h           — lock-free SPSC ring buffer для broadcast-очереди
│   └── protocol.h                  — кодирование/декодирование фреймов (header-only)
└── log/
    └── logger.cpp/h                — логгер с ротацией файлов и настраиваемым часовым поясом

Потоковая модель

tcbridge использует три рабочих потока:

IO-поток — единственный поток, обслуживающий все TCP-сокеты. Принимает новые подключения, читает команды от command-клиентов (неблокирующий конечный автомат), отправляет DLL-ответы обратно клиентам. Использует WSAWaitForMultipleEvents для мультиплексирования событий.

DLL-поток — выделенный поток для вызовов SendCommand. IO-поток кладёт команды в очередь, DLL-поток извлекает их, вызывает DLL и возвращает ответы через вторую очередь. Это изолирует потенциально долгие вызовы DLL от сетевого I/O.

Broadcast-поток — рассылает callback-сообщения stream-клиентам. DLL callback кладёт сообщение в lock-free ring buffer и возвращается мгновенно (требование документации TRANSAQ — не блокировать callback). Broadcast-поток извлекает сообщения из буфера и отправляет всем подключённым stream-клиентам.

Ключевые решения

Два типа каналов. DLL TRANSAQ имеет два потока данных: синхронные команды (SendCommand → ответ) и асинхронные callback-и (рыночные данные, обновления заявок, статусы). tcbridge отображает их на два типа TCP-каналов, позволяя клиентам иметь выделенные соединения для каждого.

Ring buffer для broadcast. Callback DLL кладёт сообщение в SPSC ring buffer фиксированного размера (настраивается через buffer_size_kb) и возвращается мгновенно. Это развязывает DLL callback и сетевой I/O: если stream-клиенты не успевают принимать данные, callback не блокируется. При переполнении буфера сообщение отбрасывается с предупреждением в лог.

Потокобезопасность DLL. Библиотека TXmlConnector не является потокобезопасной. Все вызовы SendCommand сериализуются через выделенный DLL-поток. Несколько command-клиентов поддерживаются — их запросы сериализуются на уровне очереди.

Wine-совместимость. Приложение кросс-компилируется MinGW под Windows и запускается под Wine в Docker-контейнере на базе Debian.

Сборка

Production (Docker)

docker build -t tcbridge .

Тесты

Тесты кросс-компилируются MinGW и запускаются под Wine:

./run_tests.sh

Запускаются пять наборов тестов:

  • test_protocol — кодирование/декодирование фреймов
  • test_tcp_server — интеграционные тесты TCP-сервера с реальными loopback-сокетами
  • test_logger — логирование с ротацией файлов
  • test_config — парсинг INI-файлов и валидация параметров
  • test_ring_buffer — SPSC ring buffer: wrap-around, переполнение, бинарные данные, конкурентный доступ

FAQ

Почему TCP, а не gRPC/REST/WebSocket? Простота. Протокол TRANSAQ уже основан на XML. Тонкий TCP-слой с length-prefixed фреймами добавляет минимальный overhead и тривиально реализуется на любом языке. Без кодогенерации, без файлов схем, без HTTP overhead.

Почему Wine, а не нативный Linux? txmlconnector64.dll - проприетарная Windows DLL без Linux-версии. Wine обеспечивает совместимый runtime с низким overhead для данного сценария (DLL в основном делает сетевой I/O к серверам TRANSAQ).

Лицензия

MIT

About

TCP-обёртка над TRANSAQ Connector. Запускает Windows-only DLL txmlconnector64.dll внутри Docker-контейнера через Wine и предоставляет к ней TCP-интерфейс, доступный с любой платформы и любого языка.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors