Сокеты
Используйте сокет SDK, чтобы подключить TCP- или UDP-клиент своего приложения через Device URnetwork. У него привычные чтение, запись, дедлайны и поведение при закрытии, а его трафик идёт по пути соединения, выбранному Device. Им можно пользоваться для одного клиента, не направляя остальную машину через VPN операционной системы.
Начните с инициализированного Device — см. Начало работы с SDK. Методы сокетов доступны в обновлённых исходниках SDK и требуют соответствующей поддержки сокетов на удалённом Device. Используйте сборки SDK, содержащие эти API, на обеих сторонах RPC-соединения.
Команды нативных менеджеров пакетов ищите на странице Установка SDK, а запускаемые интеграции сокетов и HTTP-библиотек на двенадцати языках, включая отдельные программы на JavaScript для Node и для браузера, — в примерах.
Чем он отличается от сокета ядра
Сокет ядра принадлежит сетевому стеку операционной системы. Сокет SDK принадлежит Device и использует внутрипроцессный стек TCP/IP. Device отправляет свои пакеты по настроенному маршруту, включая выбранного провайдера, когда подключён через URnetwork.
| Сокет ядра | Сокет SDK | |
|---|---|---|
| Сетевой путь | Таблица маршрутизации ОС и выбор интерфейса | Маршрутизация Device, выбор провайдера и политика |
| Интерфейс приложения | Файловый дескриптор или платформенный объект сокета | net.Conn в Go, Conn в JS, хендл в C или Socket на мобильных платформах |
| Область действия | Соединение приложения в сети хоста | Соединение приложения, которым владеет один Device |
| Нужна ли для этого соединения системная VPN | Зависит от настройки маршрута ОС | Интерфейс TUN/VPN в ОС не требуется только ради вызовов сокетов SDK |
| Локальный адрес | Интерфейс/адресное пространство хоста | Виртуальный адрес в стеке пользовательского пространства Device |
| Закрытие Device | Не связано | Закрывает его соединения SDK |
| Опции сокета и слушатели | Платформозависимые API ОС | Только исходящие соединения; нет ни файлового дескриптора, ни произвольных опций сокета, ни API прослушивания |
Виртуальный localAddr — не публичный IP выхода провайдера, и привязка к нему не делает ваше приложение достижимым из интернета. Нижележащее соединение URnetwork и провайдер по-прежнему могут пользоваться сетью операционной системы. Сокет SDK сам по себе не меняет настроенный режим маршрутизации Device и не создаёт соединения с провайдером.
TLS и DTLS шифруют соединение приложения до его назначения. Простые TCP и UDP сохраняют открытый протокол приложения; транспортное шифрование URnetwork до провайдера не превращает этот протокол в TLS до назначения.
Сети и имена хостов
Устанавливайте соединение с host:port, указывая одну из этих сетей:
| Сеть | Поведение |
|---|---|
tcp | TCP с Happy Eyeballs по IPv4/IPv6 для имени хоста |
tcp4, tcp6 | TCP, ограниченный этим семейством адресов |
udp | UDP; для имени хоста с обоими семействами адресов пир выбирается гонкой первой датаграммы/ответа |
udp4, udp6 | UDP, ограниченный этим семейством адресов |
Литералы IPv6 заключайте в квадратные скобки, например [2001:db8::10]:443. Для разрешения имён хостов используются резолвер сокетов Device и его пакетный путь. Когда провайдер недоступен, откат к разрешению или открытию назначения напрямую через хост не происходит.
Happy Eyeballs для TCP устраивает гонку попыток соединения. Методы установки соединения TLS/DTLS выбирают семейство после того, как его защищённое рукопожатие завершится успешно. Явные имена семейств и литеральные адреса обходят гонку между двумя семействами.
UDP: возможная доставка дубликатов
У UDP нет рукопожатия при установке соединения. Для udp, когда у имени есть и DNS-запись A, и AAAA, первая операция записи уходит на IPv6, а через 250 мс без ответа — на IPv4. Немедленная ошибка записи в IPv6 запускает откат раньше. Начальная датаграмма приложения может дойти до обоих адресов. Первый ответ выбирает пира, и последующие операции записи идут только к этому пиру.
Когда доставка дубликатов важна, используйте идентификаторы запросов или другой механизм обработки дубликатов на уровне приложения. Успешная первая операция записи не доказывает доставку и не выбирает пира. Если сервер так и не ответит, последующие операции записи ждут выбора до своего дедлайна или закрытия. Для протоколов, работающих только на отправку, используйте udp4, udp6 или литеральный IP. Ответ нулевой длины — допустимый ответ.
Каждая операция записи UDP — одна датаграмма. Каждое чтение потребляет одну датаграмму; если буфер чтения мал, оставшиеся байты отбрасываются. Пустая датаграмма — это данные, а не EOF. Укладывайте сообщения в ограничения протокола назначения и пути.
Go
DeviceLocal и DeviceRemote предлагают Dial, DialContext, DialTls и DialTlsContext. Обычные методы установки соединения используют те же сигнатуры, что и net.Dialer в Go, и возвращают соединение, совместимое с net.Conn.
// device is an initialized sdk.Device.
conn, err := device.DialContext(ctx, "tcp", "example.com:80")
if err != nil {
return err
}
defer conn.Close()
if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
return err
}
_, err = conn.Write([]byte("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"))Существующий HTTP-клиент может использовать Device напрямую:
transport := &http.Transport{DialContext: device.DialContext}
defer transport.CloseIdleConnections()
client := &http.Client{Transport: transport, Timeout: 20 * time.Second}
// net/http performs normal HTTPS certificate verification above this dialer.Для прямого шифрования вызовите device.DialTlsContext(ctx, "tcp", "example.com:443", nil). TCP использует TLS; UDP — DTLS 1.2. При конфигурации TLS, равной nil, используется обычная проверка сертификатов. Имя сервера по умолчанию берётся из исходного имени хоста. DTLS поддерживает меньшую поверхность конфигурации, чем TLS в Go, и отвергает неподдерживаемые опции безопасности.
Чтение и запись могут вернуть частичные данные вместе с ошибкой; обрабатывайте возвращённые байты. Контекст установки соединения управляет установкой, а не временем жизни успешного соединения. Для последующего ввода-вывода задавайте абсолютные дедлайны, а чтобы снять их, используйте time.Time{}. Закончив, закройте соединение. Предел по умолчанию на установку соединения и защищённое рукопожатие — 30 секунд; более ранний дедлайн вызывающего его сокращает.
JavaScript и TypeScript
Обёртки Device в SDK предоставляют методы dial и dialTls на основе Promise. Страница браузера использует настроенный удалённый Device с поддержкой сокетов. SDK открывает удалённое соединение через WASM; ему не нужны ни нативная поддержка Direct Sockets в браузере, ни упаковка в Isolated Web App.
const conn = await device.dialTls("tcp", "example.com:443", undefined, {
timeoutMillis: 5000,
});
try {
await conn.setDeadline(Date.now() + 5000);
await conn.write(new TextEncoder().encode(
"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"
));
for (let chunk; (chunk = await conn.read()) !== null;) {
console.log(new TextDecoder().decode(chunk));
}
} finally {
await conn.close();
}read() возвращает Uint8Array или null при EOF. Пустой массив — допустимая UDP-датаграмма. readable и writable предоставляют адаптеры Web Streams; для каждого направления выберите либо прямые методы, либо адаптеры. Закрытие потока TCP отправляет FIN со стороны записи, если это поддерживается. Явный close() закрывает всё соединение.
Чтобы отменить открытие, используйте AbortSignal. Для установленных сокетов используются дедлайны и закрытие. Методы дедлайнов принимают миллисекунды эпохи Unix, Date или null, чтобы снять дедлайн. Ошибка частичной записи содержит bytesWritten; частичные данные чтения возвращаются первыми, а сопутствующая им ошибка — при следующем прямом чтении. Трафик сокета останавливается, когда отключается владеющий им удалённый сервис; после переподключения он не воспроизводится повторно.
API Direct Sockets
Используйте сигнатуры конструкторов Direct Sockets с UR Device:
const {TCPSocket, UDPSocket} = device.directSockets;
const socket = new TCPSocket("echo.example", 9000);
const {readable, writable} = await socket.opened;
const reader = readable.getReader({mode: "byob"});
const writer = writable.getWriter();
try {
await writer.write(new TextEncoder().encode("hello"));
await writer.close();
console.log(await reader.read(new Uint8Array(1024)));
} finally {
await Promise.allSettled([reader.cancel(), writer.abort()]);
reader.releaseLock(); writer.releaseLock();
await socket.close();
await socket.closed;
}Для UDP создайте new UDPSocket({remoteAddress: "echo.example", remotePort: 9001}). Дождитесь opened, затем записывайте {data: new Uint8Array([1, 2, 3])} и читайте value.data. Каждый объект — одна датаграмма, включая датаграмму нулевой длины. Сообщения подключённого UDP опускают поля удалённого адреса и отвергают переопределение назначения для отдельного сообщения.
Экспортируемая фабрика createDirectSockets(device) тоже возвращает эти конструкторы. У обоих интерфейсов есть промисы opened и closed и асинхронный close(). TCP поддерживает читателей по умолчанию и BYOB-читателей, а также запись BufferSource. Закрытие его потока записи отправляет FIN, а чтение при этом остаётся доступным. Перед закрытием сокета отмените или прервите ожидающие операции и снимите блокировки читателя и писателя; иначе close() отклоняется с InvalidStateError. Сетевые сбои приводят к отклонению с NetworkError.
Нативный API Chrome доступен приложениям Isolated Web Apps. Реализация SDK работает в обычных браузерах и в Node через настроенный Device, без пакета IWA и без нативного разрешения Direct Sockets. Она не подменяет глобальные объекты браузера. См. документацию Chrome и предложение Direct Sockets.
Этот релиз реализует исходящий TCP и подключённый UDP. Чтобы ограничить разрешение имён, используйте dnsQueryType: "ipv4" или "ipv6"; если параметр опущен, сохраняется Happy Eyeballs самого Device. Привязанный UDP, мультикаст, слушатели и настройка буфера/no-delay/keep-alive для отдельного сокета недоступны, и корректные запросы этих возможностей завершаются ошибкой NotSupportedError. Это профиль совместимости для клиентов, а не полный браузерный API.
Для имён UDP с обоими семействами адресов промис opened выполняется до отправки. Его поля конечной точки сначала описывают первого кандидата и обновляются после получения первого ответа. Начальная датаграмма может дойти до обоих адресов. Если конечная точка должна быть фиксированной уже при открытии, выберите литеральный IP или семейство DNS. Примеры используют таймер, чтобы отменять зависший потоковый ввод-вывод; отдельный API Conn к тому же предоставляет дедлайны.
Конструкторы Direct Sockets открывают простые соединения TCP/UDP. Для TLS/DTLS используйте dialTls. Запускаемые примеры на JavaScript для Node и браузера и пример на TypeScript включают эхо по TCP/UDP, тайм-ауты, очистку и интеграцию с HTTP-библиотеками.
Нативные биндинги и поддерживаемые платформы
| Биндинг | Поверхность сокетов и платформа |
|---|---|
| Go | Поведение net.Conn на целевых платформах Go, которые поддерживает SDK |
| Android Kotlin/Java | Переносимые OpenSocket/Socket в AAR; Android API 24+ с поставляемыми ABI |
| Apple Swift | Переносимые OpenSocket/Socket в XCFramework; iOS 16+ и macOS 13.5+ с поставляемыми срезами для устройств и симулятора |
| C/C++ и другие FFI-клиенты | C ABI для Windows 10+ и Linux glibc 2.35+ на amd64/arm64; сборки для хоста macOS — для разработки |
| JS/TS в браузере и Node | WASM, Conn и Web Streams в Direct Sockets, плюс доступный эндпоинт Device RPC с поддержкой сокетов |
Мобильный код вызывает OpenSocket(network, address, timeoutMillis, tlsOptions). Опции TLS, равные nil, запрашивают простое соединение; конфигурация, отличная от nil, запрашивает TLS/DTLS. Socket.Read возвращает результат с Data и Eof; методы дедлайнов принимают миллисекунды эпохи Unix, а ноль снимает дедлайн. Для блокирующих операций используйте рабочий поток или подходящий диспетчер корутин.
Код на C вызывает urnet_device_dial / urnet_device_dial_tls, а затем urnet_conn_read, urnet_conn_write и функции дедлайнов и закрытия. Чтение возвращает число байтов и отдельный флаг EOF. Оно потребляет данные сразу; это не запрос размера выходного буфера. Обрабатывайте частичное число байтов, даже когда возвращается строка ошибки. Строки ошибок и адресов освобождайте через urnet_free_string, а хендл соединения — через urnet_release, который его заодно и закрывает.
Сейчас SDK предоставляет клиентские соединения. Серверные сокеты и сокеты-слушатели появятся отдельным дополнением с явной семантикой достижимости и владения. Модель биндингов и сборки описана в туре по SDK, а настройка Device — в начале работы.