Запустить удаленный помощник сбис для виндовс

Обновлено: 04.07.2024




Опыт — сын ошибок трудных

Систем удаленного доступа существует достаточно много. Это и всевозможные вариации бесплатных VNC, и достаточно мощные и предлагающие широкий набор функционала платные решения.Изначально наша компания использовала адаптацию одного из таких решений — UltraVNC. Это отличная бесплатная система, которая позволяет подключиться к другому ПК, зная его IP. Вариант того, как стоит поступать, если ПК имеет непрямой доступ к сети интерне, уже мелькал на просторах Хабра, и мы не будем затрагивать эту тему. Этого решения будет достаточно только до достижения сравнительно небольшого количества одновременных подключений. Шаг влево, шаг вправо, и начинается головняк с масштабированием, удобством использования, интеграцией в систему и сложностью доработок, которые, конечно, появляются в процессе жизненного цикла ПО, с чем мы и столкнулись.


Итак, было принято решение изобрести свой велосипед создать свою систему управления удаленными рабочими столами, которую можно было бы интегрировать в общую экосистему СБИС. Конечно, самый простой способ связать 2 ПК, который не использует только ленивый — по числовому идентификатору. В нашей реализации мы используем рандомные 6-и знаковые номера без привязки к конкретному клиенту.

Один очень известный человек однажды сказал:


Теория — это когда все известно, но ничего не работает.
Практика — это когда все работает, но никто не знает почему.
Мы же объединяем теорию и практику: ничего не работает…
и никто не знает почему!

В самом начале нашего пути, эта цитата была очень похожа на правду: было понимание каким образом можно «познакомить» друг с другом клиента и оператора. Но на практике все оказалось не совсем тривиально.

Введение в p2p

Для связи 2х устройств мы используем сигнальный сервер — посредник, доступ к которому есть у обеих сторон. Его роль заключается в регистрации и возможности обмена информацией между участниками в режиме реального времени. Через него без лишних хлопот мы производим обмен endpoint’ами (связка IP-адрес и порт, точка доступа) с целью установки соединения.


Этот сигнальный сервер, именуемый у нас remote helper manager(RHM) — пул написанных на nodejs систем, обеспечивающих отказоустойчивую работу всего сервиса. Нууу, точнее, как «отказоустойчивую» … мы на это надеемся :). Подключение к одному из серверов происходит по принципу round-robin. Таким образом клиент и оператор могут быть подключены к разным серверам, и вся механика по их синхронизации и координации полностью снята с десктопного приложения.

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


Кстати, не поступайте как мы – не стреляйте себе в ногу: если используете 443 TCP порт — используйте TLS, а не чистый трафик. Все больше и больше брандмауэров его блокируют и разрывают соединение, причем, нередко на стороне провайдера.


Самые распространенные в сети интернет протоколы обмена информацией — это UDP и TCP. UDP — быстр и легок, однако лишен нативной возможности гарантировать доставку пакетов и их очередность. TCP лишен этих недостатков, однако чуть более сложен в процессе установки p2p соединения. А с последними тенденциями, как мне кажется, прямое tcp соединение и вовсе может кануть в лету.

Далеко не всегда установка p2p соединения зависит от умения работать с сетевыми протоколами. По большей части эта возможность зависит от конкретных сетевых настроек, чаще: типа NAT(Network address translation) и/или настроек файрвола.

Принято разделять NAT на 4 типа, каждый из которых отличаются правилами трансляции пакетов из внешней сети конечному пользователю:

  • Symmetric NAT
  • Cone/Full Cone NAT
  • Address restricted cone NAT
  • Port restricted cone NAT

В большинстве случаев удается пробиться через NAT, инициировав передачу данных к узлу сети, от которого ожидаешь получить ответ. Для этого необходимо, чтобы удаленная сторона узнала свой внешний endpoint и сообщила его нам. Нам, в свою очередь, необходимо сделать то же самое.

Чтобы узнать свой IP-адрес и порт на внешнем устройстве (для простоты назовем его маршрутизатором), мы используем STUN (Session traversal utilities for NAT) и TURN (Traversal using relay NAT) сервера. STUN – для определения внешних IP: порт(endpoint) на UDP протокола, TURN – для TCP.

Почему так, ведь гораздо проще было бы получить внешний IP с нашего же сигнального сервера?

Здесь имеется как минимум 4 аргумента «за»:

  1. Возможность прозрачного расширения списка серверов (как своих, так и общедоступных) для сбора endpoint’ов, таким образом повысить отказоустойчивость системы.
  2. Взаимодополняемость и широкое распространение протоколов STUN и TURN позволяет уделять минимум внимания на сбор endpoint’ов и ретрансляцию трафика.
  3. STUN и TURN протоколы очень похожи. Разобравшись с архитектурой STUN пакетов, TURN идет уже по «накатанной». А использование TURN дают нам возможность ретрансляции трафика при провале попытки установить прямое подключение.
  4. У нас уже использовался STUN/TURN сервер «coturn» в проекте видеозвонков, а значит можно было «заюзать» их мощности с минимальными вливаниями в «железо».

Как же строится общение с сервером по STUN/TURN протоколу


  1. 2 байта на тип атрибута
  2. 2 байта на его длину
  3. самого значения атрибута

Как выглядит сбор endpoint’а для UDP протокола:


  1. Коннект к серверу
  2. Отправка пакета, содержащего binding request:
  3. Получение пакета, содержащего binding response:
  4. Парсинг пакета и извлечение mapped-address:
    0x00 0x01 — Тип атрибута, соответствующий MAPPED-ADDRESS
    0x00 0x08 — Совокупная длина атрибута
    0x00 0x01 — Версия протокола, соответствующая IPv4
    0x30 0x39 – Порт, со значением 12345

Сбор endpoint’а для TCP несколько отличается, т.к. получаем мы его по TURN протоколу. Почему именно так? Все объясняется минимизацией количества сокетов, подключенных к TURN-серверу, а значит, потенциально большее количество людей смогут «висеть» на одном сервере ретрансляции трафика.

Для сбора кандидата по TURN протоколу необходимо:

Конечно, это сейчас кажется простым и понятным, но оглядываясь назад, когда смотришь в RFC и понимаешь, что без подсказок wireshark’а дальше дело не сдвинется с мертвой точки — готовишься к погружению в… В общем, вспоминается один бородатый анекдот:


Как установить соединение?

Самое простое – это организация UDP hole punch’а.
Для этого необходимо искусственно создать правила маршрутизации на своем NAT.


Достаточно просто организовать серию передачи пакетов на удаленный endpoint и дождаться от него ответ. Несколько пакетов необходимы для создания соответствующего правила на NAT’е и избавления от «гонки», кто кому первым доставит соответствующий пакет. Ну и потерю на UDP никто не отменял.

Далее обменялись контрольными фразами и можно считать, что соединение установлено.

Чуть-чуть сложнее – организация TCP hole punch, хотя общая идеология остается точно такой же.

Сложность заключается в том, что только 1 сокет по умолчанию может занимать свой локальный endpoint, а попытка подключения к другому адресу приведет к автоматическому разрыву соединения с первым. Однако существуют опции сокета, это ограничение снимающие: REUSE_ADDRESS и EXCLUSIVEADDRUSE. После взведения первой и сбрасывания второй опции на сокете другие сокеты смогут занимать тот же самый локальный endpoint.

Ну и остается сущий пустяк – забиндиться на локальный endpoint, открытый сокетом при коннекте с TURN’ом, ну и попытаться подключиться к endpoint’у удаленной стороны.

Ну и еще чуть сложнее, но не менее важная для стабильной установки соединения – ретрансляция трафика.

Почему мы унесли прямое udp на второе место?

Что ж, UDP при всей своей легкости и скорости обладает существенным недостатком: отсутствием гарантии доставки и очередности. И если с видеопотоком еще как-то с этим можно было бы смириться (наличие графических артефактов), то вот с передачей файлов тут несколько серьезней.

Для обеспечения гарантии и очередности был реализован механизм, схожий с reliable UDP, который да, потребляет несколько больше ресурсов, но и дает желаемое.
Как же мы вышли из ситуации? Для начала необходимо узнать MTU (maximum transmission unit) – то есть максимально большой размер udp пакета, который может быть отправлен без фрагментирования на проходящих узлах.

Для этого принимаем за максимальный размер пакета 512 байт и выставляем сокету опцию IP_DONTFRAGMENT. Отправляем пакет и ждем его подтверждения. Если в течение фиксированного времени мы получили ответ, то увеличиваем максимальный размер и повторяем итерацию. Если же в конечном итоге подтверждения мы не дождались, то начинаем процедуру уточнения размера MTU: начинаем не существенно понижать максимальный размер блока и ожидаем стабильного подтверждения в течение 10 раз. Не получили подтверждение – снизили MTU и по новой запускаем цикл.
Оптимальный размер MTU найден.

Далее проводим сегментирование: нарезаем весь большой блок на множество маленьких с указанием начального номера сегмента и конечного номера сегмента, характеризующего пакет. После разбиения добавляем сегменты в очередь отправки. Отправка сегмента производится до тех пор, пока удаленная сторона не сообщит нам о том, что получила его. Интервал повторной отправки используем как 1.2*максимальный размер ping’а, полученного при нахождении MTU.
На принимающей стороне смотрим полученный сегмент, добавляем во входящую очередь и пробуем собрать ближайший пакет. Если получилось – чистим очередь и пробуем собрать следующий.

Тут, конечно, самые внимательные из вас, кто «дожил» до этого абзаца, могут смело заметить: а почему не использовать кодек x264 или x265? — и будут частично правы. Честно говоря, мы тоже склонны его заюзать, тогда можно поступиться этим велосипедом на udp. Но как быть, скажем, с передачей бинарных файлов? В этом случае мы опять возвращаемся к необходимости гарантии доставки и очередности пакетов.

В заключение хочется отметить, что с такой организацией подключений мы имеем не более 2-3% несостоявшихся подключений в день, большую часть из которых составляют неверные настройки прокси или файрвола, настроив которые соединение осуществляется без проблем.

Если эта тема вам окажется интересна (а нам она кажется таковой), то в следующих статьях мы расскажем о запуске приложения с наивысшими правами в системе, проблемах, которые из-за этого образуются, и как мы с ними боремся. Об алгоритмах сжатия, виртуальных рабочих столах и многом другом.

Читайте также: