Тема: P2P крізь NAT, як це працює
Письменник з мене ніякий, але дуже хотілось би поділитися тим що “UDP hole punching” це легко. То му що таке InternetPotocol які є типи NAT чим, відрізняється TCP від UDP я писати не буду. Про все це є на вікіпедії. А розповім я про реалізацію технології “UDP hole punching” під windows за допомогою звичайної сішечки.
Суть цієї технології в тому що NAT при певній умові може маршрутизувати UDP датаграму від інтернет хосту до певного хоста в локальній мережі. А умова наступна – від хосту з локальної мережі повинна бути направлена UDP датаграма до інтернет хосту, від якого потрібно приймати UDP датаграми. Тобто якщо два хости з різних локальних мереж, за різними NAT направлять назустріч друг другу UDP датаграми, то вони зможуть напряму обмінюватися даними. Але для цього потрібно знати адресу свого хосту та хосту партнера зі сторони NAT, а саме айпі адресу та вихідний порт. Тут на допомогу приходить наступна технологія – “STUN”. Про яку також все є на вікіпедії. На практиці по кроково це виглядає так:
1. Запит до STUN сервера
2. Отримуємо айпі адресу свого NAT та вихідний порт
3. Повідомляємо їх партнеру
4. Отримуємо від партнера його адресу та вихідний порт
5. Відсилаємо UDP датаграми партнеру
6. Очікуємо UDP від партнера
7. Отримуємо UDP датаграму від партнера
8. Прямий обмін тепер даними можливий
“UDP hole punching” виконано. Так це працює не зі всіма типами NAT, але типовий NAT типового домашнього користувача інтернетів це дозволяє.
Формат обміну даними зі STUN наступний
Запит:
struct STUN_REQ//stun request
{
UINT16 type;
UINT16 length;
UINT32 magic;
UINT8 tsx_id[12];
};
Відповідь:
struct STUN_RESP//response from stun server
{
UINT16 type;
UINT16 length;
UINT32 magic;
UINT8 tsx_id[12];
unsigned char unknown[5];
unsigned char family;//0x01:IPv4 0x02:IPv6
unsigned short port;
unsigned int addr;
};
tsx_id – виконуй роль певного «токену», краще заповнювати рандомногенерованими даними.Мейджик це мейджик і у випадку STUN завжди має значення 0x2112A442. Type це тип запиту, запит від клієнта - 0x0001, відповідь від сервера - 0x0101. Length це відповідно кіількіість додаткових даних, у нашому випадку просто нуль.
Комунікація зі STUN сервером звісно ж проходить через UDP протокол.
Після того як координати за NAT з’ясовані, та відомі обом сторонам, залишається розпочати надсилати UDP датаграми, на зустріч друг другу, тут нічого складного, звичайні sendto та recvfrom.
Для більш наглядної демонстрації,я написав трохи примітивного коду(такий собі консольний чат) https://github.com/yoosYyd/P2Particle1
Ось кілька скринів, як воно працює
В вас може з'явитися логічне питання, як двома хостам обмінятися своїми адресами за NAT ? Так це є проблемою, але в неї є багато рішень, наприклад - XMPP. Але звісно для відладки без віддаленої машини, з доступом через RDP або TeamViewer не обійтися.