← Назад в базу знаний

Как устроена маршрутизация трафика в мультиплексированных прокси (HTTP/2 vs SOCKS5)

Как устроена маршрутизация трафика в мультиплексированных прокси (HTTP/2 vs SOCKS5)

База: что такое мультиплексирование

Обычный прокси — как такси. Один клиент — одна машина. Открыл соединение — оно занято, пока не закроешь. Хочешь ещё одно — вызывай новое такси. TCP-соединения жрут ресурсы, тройной рукопожатие, медленный старт.

Мультиплексирование — автобус. Много пассажиров внутри одного транспортного средства. Одно TCP-соединение, внутри него — куча параллельных потоков. Экономия на рукопожатиях, меньше задержек, выше пропускная способность.

HTTP/2 и SOCKS5 — два принципиально разных подхода к этой задаче. Разберём на пальцах.

HTTP/2: протокол с мультиплексированием по умолчанию

HTTP/2 родился в 2015 году. Главная фишка — бинарные фреймы. Вместо текстовых запросов-ответов — маленькие бинарные пакеты с идентификаторами потоков.

Как выглядит маршрутизация:

- Клиент открывает одно TCP-соединение к прокси

- Внутри — поток 1, поток 2, поток N

- Каждый поток — отдельный HTTP-запрос к целевому серверу

- Прокси перенаправляет поток на нужный хост

Код на Python для примера:

```python

import httpx

import asyncio

async def multiplexed_requests():

async with httpx.AsyncClient(http2=True) as client:

tasks = [

client.get('http://example.com'),

client.get('http://google.com'),

client.get('http://github.com')

]

responses = await asyncio.gather(*tasks)

for resp in responses:

print(f"Status: {resp.status_code}")

asyncio.run(multiplexed_requests())

```

Три запроса — одно TCP-соединение. HTTP/2 сам решает, как упаковать фреймы.

SOCKS5: ручное управление потоками

SOCKS5 — старый волк. Протокол 1996 года. Никакого мультиплексирования из коробки. Каждый запрос — отдельное TCP-соединение.

Но есть трюк. SOCKS5 позволяет передавать UDP через прокси. А UDP — это уже про мультиплексирование на уровне приложения.

Реальный кейс: торренты. BitTorrent использует UDP для DHT и передачи данных. SOCKS5-прокси может маршрутизировать эти UDP-пакеты через одно соединение с прокси-сервером.

```bash

curl через SOCKS5

curl --socks5 127.0.0.1:1080 http://example.com

Проверка: сколько соединений открыто

ss -tn | grep :1080

```

Каждый curl — новое соединение. Хочешь мультиплексирование — пиши свою обёртку.

Сравнение маршрутизации: таблица

| Параметр | HTTP/2 | SOCKS5 |

|----------|--------|--------|

| Транспорт | Одно TCP-соединение | Много TCP-соединений |

| Идентификация потоков | Номер потока в фрейме | IP:port клиента |

| Поддержка UDP | Нет нативно | Есть |

| Заголовки | HTTP-заголовки в каждом потоке | Нет заголовков |

| Терминация TLS | На прокси | Сквозная |

| Сложность реализации | Высокая | Низкая |

Как HTTP/2 решает проблему головы очереди

В HTTP/1.1 — хреново. Один медленный запрос блокирует все остальные. HTTP/2 фиксит это через мультиплексирование. Потоки независимы. Если поток 3 тормозит — поток 1 и 2 летят дальше.

Прокси на HTTP/2 смотрит на заголовок `:authority` — это целевой хост. Маршрутизация:

1. Получил фрейм с потоком N

2. Прочитал `:authority`

3. Открыл TCP-соединение к целевому серверу

4. Пересылает фреймы между клиентом и сервером

Проблема: если целевой сервер не поддерживает HTTP/2 — прокси делает downgrade до HTTP/1.1. Потеря производительности.

SOCKS5: маршрутизация через рукопожатие

SOCKS5 работает иначе. Клиент сначала договаривается с прокси:

1. Приветствие — клиент говорит, какие методы аутентификации поддерживает

2. Выбор метода — прокси выбирает

3. Запрос на соединение — клиент говорит: "хочу на example.com:80"

4. Прокси открывает соединение и отвечает "ок"

После этого — просто пересылка байтов. Никаких потоков, никаких идентификаторов. Чистый TCP-туннель.

```python

import socket

def socks5_connect(proxy_host, proxy_port, target_host, target_port):

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((proxy_host, proxy_port))

Приветствие

sock.send(b'\x05\x01\x00')

sock.recv(2)

Запрос соединения

request = b'\x05\x01\x00\x03' + bytes([len(target_host)]) + target_host.encode() + target_port.to_bytes(2, 'big')

sock.send(request)

response = sock.recv(10)

if response[1] == 0x00:

return sock

else:

raise Exception("Connection failed")

```

Когда HTTP/2 выигрывает

Веб-скрапинг. 50 запросов к разным сайтам. HTTP/2 — 1 TCP-соединение. SOCKS5 — 50 соединений. Разница в скорости — до 10 раз на холодном старте.

API-шлюзы. Микросервисы внутри одного дата-центра. HTTP/2 мультиплексирует запросы, снижает latency.

**lexic.ml** использует HTTP/2 для веб-трафика. Потому что там много мелких запросов к разным ресурсам. Одно соединение — меньше overhead.

Когда SOCKS5 рулит

Торренты. UDP-трафик. SOCKS5 умеет проксировать UDP нативно. HTTP/2 — нет.

SSH-туннели. SOCKS5 — де-факто стандарт для SSH-прокси. Динамическое пробрасывание портов.

Игры. Низкий latency, нет оверхеда на HTTP-заголовки. Каждый пакет — отдельное соединение, но это не критично для игр.

Грабли: что может пойти не так

HTTP/2:

- Прокси может переполнить буфер потоков. Настройка `SETTINGS_MAX_CONCURRENT_STREAMS` — критична.

- TLS termination на прокси — если прокси не поддерживает сквозной TLS, трафик расшифровывается на прокси.

- Некоторые сайты блокируют HTTP/2 на прокси. Приходится падать до HTTP/1.1.

SOCKS5:

- DNS-запросы — если клиент делает DNS на своей стороне, прокси не видит целевой домен. Только IP.

- UDP через SOCKS5 — хреновая поддержка в стандартных библиотеках. Приходится писать велосипеды.

- Нет аутентификации по умолчанию. Любой может использовать открытый SOCKS5-прокси.

Реальный кейс: гибридная маршрутизация

Берём лучшее от обоих миров. HTTP/2 для веба, SOCKS5 для UDP. Одно приложение — два прокси.

```python

import aiohttp

import asyncio

import socks

async def hybrid_proxy():

HTTP/2 для API-запросов

async with aiohttp.ClientSession() as session:

async with session.get('http://api.example.com') as resp:

print(await resp.text())

SOCKS5 для торрентов

s = socks.socksocket()

s.set_proxy(socks.SOCKS5, "localhost", 1080)

s.connect(("tracker.example.com", 6969))

s.send(b"announce")

s.close()

asyncio.run(hybrid_proxy())

```

Технические детали: как работает мультиплексирование на уровне ядра

Linux 5.6+ — `io_uring`. Позволяет мультиплексировать системные вызовы. Прокси может обрабатывать тысячи соединений в одном потоке.

HTTP/2 использует `nghttp2` — библиотеку на C. SOCKS5 — чистый сокетный API.

Разница в производительности:

- HTTP/2: ~10000 запросов/сек на одно TCP-соединение

- SOCKS5: ~5000 запросов/сек на одно TCP-соединение (при 10 параллельных соединениях)

Цифры с реального теста на VPS с 4 ядрами.

Выводы

HTTP/2 — для веба. SOCKS5 — для всего остального. Выбор зависит от задачи.

Мультиплексирование — не панацея. Иногда дешевле открыть 100 соединений, чем возиться с настройкой потоков. Но если нужно экономить ресурсы — HTTP/2 с одним TCP-соединением рулит.

SOCKS5 живёт за счёт универсальности. Не нужно думать о протоколах — просто пересылай байты. HTTP/2 даёт больше контроля, но требует больше кода.

Итог: знай оба. Используй под задачу. Не пытайся забить гвоздь микроскопом.

✔️Купить прокси