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скачивается с сайта ФИНАМ (в репозиторий не включена)
-
Поместите
txmlconnector64.dllв корень проекта. -
Настройте
config.ini(см. раздел Конфигурация). -
Сборка и запуск:
docker build -t tcbridge .
docker run -d --name tcbridge -p 9090:9090 tcbridgeИли через docker compose:
docker compose -f compose.dev.yaml up -d- Подключайтесь к
localhost:9090.
Настройка выполняется через файл config.ini в формате INI. По умолчанию tcbridge ищет config.ini в рабочей директории. Путь можно переопределить через переменную окружения TCBRIDGE_CONFIG:
TCBRIDGE_CONFIG=/path/to/my_config.ini wine tcbridge.exeФайл разделён на три секции: [server], [logging] и [timeouts]. Поддерживаются комментарии через # и ;.
[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| Параметр | По умолчанию | Диапазон | Описание |
|---|---|---|---|
dll_path |
txmlconnector64.dll |
— | Путь к DLL внутри контейнера |
port |
9090 |
1–65535 | TCP-порт для входящих подключений |
buffer_size_kb |
1024 |
64–16384 | Размер ring buffer для broadcast-сообщений (КБ) |
| Параметр | По умолчанию | Диапазон | Описание |
|---|---|---|---|
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 и выше |
| Параметр | По умолчанию | Диапазон (мс) | Описание |
|---|---|---|---|
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_msTCP 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-команд и ответов полностью соответствует документации 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.
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, переполнение, бинарные данные, конкурентный доступ
Почему 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