UPNP
Наследует: RefCounted < Object
Функции Universal Plug and Play (UPnP) для обнаружения сетевых устройств, запросов и переадресации портов.
Описание
Этот класс можно использовать для обнаружения совместимых UPNPDevice в локальной сети и выполнения команд на них, таких как управление сопоставлениями портов (для переадресации портов/обхода NAT) и запрос локального и удаленного сетевого IP-адреса. Обратите внимание, что методы этого класса являются синхронными и блокируют вызывающий поток.
Чтобы перенаправить определенный порт (здесь 7777, обратите внимание, что и discover(), и add_port_mapping() могут возвращать ошибки, которые следует проверить):
var upnp = UPNP.new()
upnp.discover()
upnp.add_port_mapping(7777)
Чтобы закрыть определенный порт (например, после того, как вы закончили его использовать):
upnp.delete_port_mapping(port)
Примечание: Обнаружение UPnP блокирует текущий поток. Чтобы выполнить обнаружение без блокировки основного потока, используйте Thread-ы следующим образом:
# Выдается после завершения настройки сопоставления портов UPnP (независимо от успеха или неудачи).
signal upnp_completed(error)
# Замените это на ваш собственный номер порта сервера в диапазоне 1024 и 65535.
const SERVER_PORT = 3928
var thread = null
func _upnp_setup(server_port):
# Запросы UPNP занимают некоторое время.
var upnp = UPNP.new()
var err = upnp.discover()
if err != OK:
push_error(str(err))
upnp_completed.emit(err)
return
if upnp.get_gateway() and upnp.get_gateway().is_valid_gateway():
upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "UDP")
upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "TCP")
upnp_completed.emit(OK)
func _ready():
thread = Thread.new()
thread.start(_upnp_setup.bind(SERVER_PORT))
func _exit_tree():
# Дождитесь завершения потока, чтобы обработать выход из игры, пока поток выполняется.
thread.wait_to_finish()
Терминология: В контексте сетей UPnP «шлюз» (или «устройство интернет-шлюза», сокращенно IGD) относится к сетевым устройствам, которые позволяют компьютерам в локальной сети получать доступ к Интернету («глобальная вычислительная сеть», WAN). Эти шлюзы часто также называют «маршрутизаторами».
Подводные камни:
Как объяснялось выше, эти вызовы являются блокирующими и не должны выполняться в основном потоке, особенно потому, что они могут блокироваться на несколько секунд за раз. Используйте потоки!
Сетевое взаимодействие является физическим и беспорядочным. Пакеты теряются при передаче или фильтруются, адреса, свободные порты и назначенные сопоставления меняются, а устройства могут покинуть сеть или присоединиться к ней в любое время. Помните об этом, будьте внимательны при проверке и обработке ошибок и обрабатывайте их изящно, если можете: добавьте понятный пользовательский интерфейс ошибок, тайм-ауты и повторную обработку.
Сопоставления портов могут измениться (и быть удалены) в любое время, и удаленный/внешний IP-адрес шлюза может измениться аналогичным образом. Вам следует рассмотреть возможность повторного запроса внешнего IP-адреса и попытаться периодически обновлять/подкреплять сопоставление портов (например, каждые 5 минут и при сбоях в работе сети).
Не все устройства поддерживают UPnP, и некоторые пользователи отключают поддержку UPnP. Вам нужно это урегулировать (например, документировать и требовать от пользователя вручную перенаправлять порты или добавлять альтернативные методы обхода NAT, такие как сервер-ретранслятор/зеркал или пробивка NAT, STUN/TURN и т. д.).
Подумайте, что происходит при конфликтах сопоставления. Возможно, несколько пользователей в одной сети захотят играть в вашу игру одновременно, или, может быть, другое приложение использует тот же порт. Сделайте порт настраиваемым и оптимально выбирайте порт автоматически (повторная попытка с другим портом в случае неудачи).
Дополнительная литература: Если вы хотите узнать больше о UPnP (и в частности об устройстве интернет-шлюза (IGD) и протоколе управления портами (PCP)), Wikipedia является хорошей первой остановкой, спецификацию можно найти на Open Connectivity Foundation и реализация Godot основана на MiniUPnP client.
Свойства
|
||
|
||
|
Методы
void |
add_device(device: UPNPDevice) |
add_port_mapping(port: int, port_internal: int = 0, desc: String = "", proto: String = "UDP", duration: int = 0) const |
|
void |
|
delete_port_mapping(port: int, proto: String = "UDP") const |
|
discover(timeout: int = 2000, ttl: int = 2, device_filter: String = "InternetGatewayDevice") |
|
get_device(index: int) const |
|
get_device_count() const |
|
get_gateway() const |
|
query_external_address() const |
|
void |
remove_device(index: int) |
void |
set_device(index: int, device: UPNPDevice) |
Перечисления
enum UPNPResult: 🔗
UPNPResult UPNP_RESULT_SUCCESS = 0
Команда UPNP или обнаружение прошли успешно.
UPNPResult UPNP_RESULT_NOT_AUTHORIZED = 1
Не авторизовано для использования команды на UPNPDevice. Может быть возвращено, если пользователь отключил UPNP на своем маршрутизаторе.
UPNPResult UPNP_RESULT_PORT_MAPPING_NOT_FOUND = 2
Для указанного порта и комбинации протоколов на указанном UPNPDevice сопоставление портов не найдено.
UPNPResult UPNP_RESULT_INCONSISTENT_PARAMETERS = 3
Несоответствующие параметры.
UPNPResult UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY = 4
Такой записи в массиве нет. Может быть возвращён, если заданная комбинация порта и протокола не найдена на UPNPDevice.
UPNPResult UPNP_RESULT_ACTION_FAILED = 5
Действие не удалось.
UPNPResult UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED = 6
UPNPDevice не допускает использования подстановочных знаков для исходного IP-адреса.
UPNPResult UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED = 7
UPNPDevice не допускает использования подстановочных знаков для внешнего порта.
UPNPResult UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED = 8
UPNPDevice не допускает использования подстановочных знаков для внутреннего порта.
UPNPResult UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD = 9
Значение удаленного хоста должно быть подстановочным знаком.
UPNPResult UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD = 10
Значение внешнего порта должно быть подстановочным знаком.
UPNPResult UPNP_RESULT_NO_PORT_MAPS_AVAILABLE = 11
Карты портов недоступны. Также может быть возвращен, если функция сопоставления портов недоступна.
UPNPResult UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM = 12
Конфликт с другим механизмом. Может быть возвращено вместо UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING, если сопоставление портов конфликтует с существующим.
UPNPResult UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING = 13
Конфликт с существующим сопоставлением портов.
UPNPResult UPNP_RESULT_SAME_PORT_VALUES_REQUIRED = 14
Значения внешнего и внутреннего порта должны быть одинаковыми.
UPNPResult UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED = 15
Поддерживаются только постоянные аренды. Не используйте параметр duration при добавлении сопоставлений портов.
UPNPResult UPNP_RESULT_INVALID_GATEWAY = 16
Неверный шлюз.
UPNPResult UPNP_RESULT_INVALID_PORT = 17
Неверный порт.
UPNPResult UPNP_RESULT_INVALID_PROTOCOL = 18
Неверный протокол.
UPNPResult UPNP_RESULT_INVALID_DURATION = 19
Неверная продолжительность.
UPNPResult UPNP_RESULT_INVALID_ARGS = 20
Недопустимые аргументы.
UPNPResult UPNP_RESULT_INVALID_RESPONSE = 21
Неверный ответ.
UPNPResult UPNP_RESULT_INVALID_PARAM = 22
Недопустимый параметр.
UPNPResult UPNP_RESULT_HTTP_ERROR = 23
Ошибка HTTP.
UPNPResult UPNP_RESULT_SOCKET_ERROR = 24
Ошибка сокета.
UPNPResult UPNP_RESULT_MEM_ALLOC_ERROR = 25
Ошибка выделения памяти.
UPNPResult UPNP_RESULT_NO_GATEWAY = 26
Нет доступного шлюза. Возможно, сначала нужно вызвать discover(), или discovery не обнаружил ни одного допустимого IGD (InternetGatewayDevices).
UPNPResult UPNP_RESULT_NO_DEVICES = 27
Нет доступных устройств. Возможно, сначала нужно вызвать discover(), или discovery не обнаружил ни одного из допустимых UPNPDevice-ов.
UPNPResult UPNP_RESULT_UNKNOWN_ERROR = 28
Неизвестная ошибка.
Описания свойств
Если true, IPv6 используется для обнаружения UPNPDevice.
Если 0, локальный порт для использования при обнаружении выбирается системой автоматически. Если 1, обнаружение будет выполнено с исходного порта 1900 (тот же, что и порт назначения). В противном случае в качестве порта будет использовано значение.
String discover_multicast_if = "" 🔗
Интерфейс многоадресной рассылки для использования при обнаружении. Использует интерфейс многоадресной рассылки по умолчанию, если он пуст.
Описания метода
void add_device(device: UPNPDevice) 🔗
Добавляет указанное UPNPDevice в список обнаруженных устройств.
int add_port_mapping(port: int, port_internal: int = 0, desc: String = "", proto: String = "UDP", duration: int = 0) const 🔗
Добавляет сопоставление для переадресации внешнего port (от 1 до 65535, хотя рекомендуется использовать порт 1024 или выше) на шлюзе по умолчанию (см. get_gateway()) на port_internal на локальной машине для указанного протокола proto (либо "TCP", либо "UDP", где UDP является значением по умолчанию). Если сопоставление портов для указанной комбинации порта и протокола уже существует на этом шлюзовом устройстве, этот метод пытается перезаписать его. Если это нежелательно, вы можете получить шлюз вручную с помощью get_gateway() и вызвать add_port_mapping() на нем, если таковой имеется. Обратите внимание, что переадресация известного порта (ниже 1024) с помощью UPnP может завершиться неудачей в зависимости от устройства.
В зависимости от шлюзового устройства, если сопоставление для этого порта уже существует, оно либо будет обновлено, либо отклонит эту команду из-за этого конфликта, особенно если существующее сопоставление для этого порта не было создано через UPnP или указывает на другой сетевой адрес (или устройство), нежели этот.
Если port_internal равен 0 (по умолчанию), то для внешнего и внутреннего порта используется один и тот же номер порта (значение port).
Описание (desc) отображается в некоторых пользовательских интерфейсах управления маршрутизаторами и может использоваться для указания того, какое приложение добавило сопоставление.
Аренда duration сопоставления может быть ограничена указанием продолжительности в секундах. Значение по умолчанию 0 означает отсутствие продолжительности, т. е. постоянную аренду, и, в частности, некоторые устройства поддерживают только эти постоянные аренды. Обратите внимание, что независимо от того, постоянная она или нет, это всего лишь запрос, и шлюз все равно может в любой момент решить удалить сопоставление (что обычно происходит при перезагрузке шлюза, при изменении его внешнего IP-адреса или на некоторых моделях, когда он обнаруживает, что сопоставление портов стало неактивным, т. е. не имело трафика в течение нескольких минут). Если не 0 (постоянно), допустимый диапазон согласно спецификации составляет от 120 (2 минуты) до 86400 секунд (24 часа).
Возможные возвращаемые значения см. в UPNPResult.
void clear_devices() 🔗
Очищает список обнаруженных устройств.
int delete_port_mapping(port: int, proto: String = "UDP") const 🔗
Удаляет сопоставление портов для заданной комбинации порта и протокола на шлюзе по умолчанию (см. get_gateway()), если таковое существует. port должен быть допустимым портом от 1 до 65535, proto может быть либо "TCP" либо "UDP". Может быть отклонено для сопоставлений, указывающих на адреса, отличные от этого, для известных портов (ниже 1024) или для сопоставлений, не добавленных через UPnP. См. UPNPResult для возможных возвращаемых значений.
int discover(timeout: int = 2000, ttl: int = 2, device_filter: String = "InternetGatewayDevice") 🔗
Обнаруживает локальные UPNPDevice. Очищает список ранее обнаруженных устройств.
Фильтры для устройств типа IGD (InternetGatewayDevice) по умолчанию, так как они управляют переадресацией портов. timeout — это время ожидания ответов в миллисекундах. ttl — это время жизни; касайтесь этого, только если вы знаете, что делаете.
См. UPNPResult для возможных возвращаемых значений.
UPNPDevice get_device(index: int) const 🔗
Возвращает UPNPDevice по указанному index.
int get_device_count() const 🔗
Возвращает количество обнаруженных UPNPDevice.
UPNPDevice get_gateway() const 🔗
Возвращает шлюз по умолчанию. Это первый обнаруженный UPNPDevice, который также является допустимым IGD (InternetGatewayDevice).
String query_external_address() const 🔗
Возвращает внешний IP адрес шлюза по умолчанию (см. get_gateway()) в виде строки. Возвращает пустую строку в случае ошибки.
void remove_device(index: int) 🔗
Удаляет устройство с адресом index из списка обнаруженных устройств.
void set_device(index: int, device: UPNPDevice) 🔗
Устанавливает устройство с индексом index из списка обнаруженных устройств на device.