Heredes — библиотека для разработчиков
Heredes — библиотека для облегчения решения ряда конкретных задач, связанных с прямым обменом данных в сети без использования ipv6.
Из встроенных возможностей можно выделить:
- облегченная установка соединения между двумя ПК не зависимо от того есть ли у них «белые» адреса или они за NAT;
- гарантированная (с подтверждением) прямая передача файлов с одного ПК на другой;
- реалтайм аудиосвязь между ПК за NAT;
- реалтайм демонстрация экрана ПК за NAT;
- проброс мыши и клавиатуры между ПК;
- прямая передача произвольных пользовательских данных между ПК за NAT;
- запись звука с удаленного ПК и сохранение скрина с удаленного монитора на локальной машине.
Тема пробоя NAT, на самом деле, не нова. Но она требует от разработчика определенных навыков, наличие STUN сервера, а лучше двух, и времени для реализации.
Heredes берет на себя вышеописанную часть, облегчая тем самым разработку приложений и позволяя сосредоточиться на задаче, будь-то прямой файлообмен, мессенджер или функционал удаленного администрирования, встроенный в Ваше приложение.
Скептики в целом могут возразить — зачем Heredes если есть WebRTC с крайне широкими возможностями.
Тем не менее, если звезды зажигают, значит это кому нибудь нужно.
Прежде всего Heredes не нацелен на межбраузерное взаимодействие и в этом его преимущество в десктопных приложениях. А именно — простота использования при написании «настольных» приложений, неприхотливость в вопросах ресурсов и да, мы постарались облегчить работу с тем, что не стандартизовано в WebRTC.
Разумеется, примеры реализации с помощью WebRTC найдутся и для нашего функционала (например, Screen Capture API реализует захват экрана частично или полностью) и может показаться что нет разницы, чье готовое решение использовать. Попробуйте, выберите наиболее удобное при разработке десктопного приложения решение именно для Вас.
Мы нацелены не на WEB — в приоритете именно десктоп и использование библиотеки в приложениях не требующих установки, экономичность в ресурсах и скорость выполнения задач.
Перейдем к краткому обзору?
Как писать с использованием Heredes
Часть 1. Прямая передача файлов за NAT это просто. Или 9 строк кода для передачи 8 эксабайт данных… или чуть более?
Рассмотрим как просто установить прямое соединение на примере вполне жизнеспособной задачи — передача фала между двумя ПК за NAT без использования облачных хранилищ, торрентов, файлообменных ресурсов, личных промежуточных серверов и других вспомогательных средств.
Ситуация вполне жизненная, кому из нас никогда не требовалось передать несколько эксабайт по сети? Задача даже при наличии промежуточного облачного хранилища еще та… ускорим ее в 2 раза, как минимум, за несколько минут...
Пример реализации на С++ ниже
//обмен файлами почти неограниченного размера между клиентами за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\WORK\\P2P\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\WORK\P2P\HEREDES\heredes.h>
int main(void)
{
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
DWORD Valid = 0;
DWORD Id = 0;
DWORD HightDword = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
//запуск асинхроннго сервера для ожидания входящих соединений
HANDLE hConn = IONWaitConnection(&Valid, &Id, NULL);
//запуск синхронного интерфейса для передачи файла
DWORD lowDword =IONSendFileToId(&Valid, &Id, NULL, &HightDword);
IONTerminate(hConn); //прерывание ожидания входящих соединений
CloseIONHandle(hConn);
return 0;
}
Не правда ли, очень лаконично вышло?
Есть явные недостатки, такие как:
- Heredes не нацелен на установление прямого коннекта между двумя ПК из одной локальной сети;
- могут возникнуть сложности в случае если оба ПК за симметричным NAT;
- данный пример не предусматривает передачу нескольких файлов за раз.
Тем не менее есть и очевидный плюс — это вполне рабочий пример с функционалом применимым даже в виде «как есть из коробки». Как минимум удобно перекинуть на край света файл размером… в пределах 8 ЭБт, хотя я лично и не пробовал пробросить такой файл — попробуете Вы и расскажите чем закончилось ))…
Мало кто поспорит с тем что программа копирования файла из каталога в каталог на локальном ПК потребует не на много меньше стулочасов сил, обладая куда меньшей ценностью как самостоятельный продукт.
Скачать пример
Часть 2. Простой UDP сервер и UDP клиент за NAT
Предположим наличие вполне жизненной ситуации — есть некий ПК, находящийся за NAT и мы хотим что б он периодически принимал входящие соединения из внешнего мира, а конкретно миром для него будет наш же UDP клиент. От слов к делу.
Пример реализации на С++ ниже
//UDP сервер, который в течении минуты слушает сеть и ожидает входящих соединений
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
int main(void)
{
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
DWORD Valid = 0;
DWORD Id = 0;
DWORD HightDword = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
//запуск асинхроннго сервера для ожидания входящих соединений
HANDLE hConn = IONWaitConnection(&Valid, &Id, NULL);
HANDLE hEv=CreateEventA(NULL,1,NULL,NULL);
WaitForSingleObject(hEv,60000);
CloseHandle(hEv);
IONTerminate(hConn); //прерывание ожидания входящих соединений
CloseIONHandlw(hConn); //прерывание ожидания входящих соединений
return 0;
}
//простейший UDP клиент, который ничего не делает
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
int main(void)
{
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
CHAR SecKey[8]; //8-ми байтный массив с ключем шифрования
DWORD Valid = 0;
DWORD Id = 0;
HANDLE hConn;
RegIONId(&Valid, &Id); //регистрация нового пользователя
hConn=CreateIONHandle();
if (IONConnectToId(hConn, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE){
MessageBoxA(NULL,"коннет установлен","состояние подключения", 48);
HANDLE hEv=CreateEventA(NULL,1,NULL,NULL);
WaitForSingleObject(hEv,60000);
CloseHandle(hEv);
}else{
MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
};
IONDisconnect(hConn); //прерывание ожидания входящих соединений
CloseIONHandle(hConn); //прерывание ожидания входящих соединений
return 0;
}
Данный пример очень бесполезен. Причина в том что такой сервер будет тихо реагировать на входящие соединения и обрабатывать все «по умолчанию», то есть игнорировать )), а клиент так же тихо удерживать соединение.
Часть 3. МФУ или клиент и сервер в одном лице
Бывает нужно, что бы приложение могло как реагировать на входящие, так и инициировать исходящие подключение. Такой подход кажется где то даже более универсальным. Напишем еще один бестолковый пример, но на этот раз толк от него будет — в дальнейшем этот код мы будем использовать как каркас, на который вешать всех собак.
//клиент-сервер over NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
int main(void)
{
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
CHAR SecKey[8]; //8-ми байтный массив с ключем шифрования
DWORD Valid = 0;
DWORD Id = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
HANDLE hCON_OUT=CreateIONHandle();
if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL==TRUE)){
}else{
MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
};
IONTerminate(hCON_IN);
IONDisconnect(hCON_OUT);
CloseIONHandle(hCON_IN);
CloseIONHandle(hCON_OUT);
FreeConsole();
return 0;
}
Часть 4. Простой консольный мессенджер за NAT
После примера бесполезного будет очень полезно написать что то наглядное. В предыдущих примерах и функция сервера IONWaitConnection и функция клиента IONConnectToId содержат параметр CBUserData установленный в NULL. тем не менее это не обязано быть так и должно так не быть если клиент-сервер обмениваются данными нестандартного формата. При передаче пользовательских данных это должна быть функция обработчик уведомления о пользовательских данных
//написать за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
HANDLE hOutput;
CBUDATA __stdcall UserDataProc(HANDLE hConn, LPVOID pAddrUserData, int datSize)
{
DWORD inSize;
WriteConsoleA(hOutput,pAddrUserData, datSize, &inSize, NULL);
return 0;
}
int main(void)
{
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
CHAR buffer[0x3E0]; //максимальный размер блока пользовательских данных 0х3Е0
DWORD bSize=0;
CHAR SecKey[8]; //8-ми байтный массив с ключем шифрования
DWORD Valid = 0;
DWORD Id = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
AllocConsole();
HANDLE hInput=GetStdHandle(-10);
hOutput=GetStdHandle(-11);
HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, (CBUDATA) &UserDataProc);
HANDLE hCON_OUT=CreateIONHandle();
if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, \
NULL, NULL, (CBUDATA) &UserDataProc)==TRUE){
while (bSize!=-1){
ReadConsoleA(hInput,&buffer,0x3E0,&bSize,NULL);
if (IONGetStatus(hCON_OUT)==6) {SendUserData(hCON_OUT,&buffer,bSize);};
if (IONGetStatus(hCON_IN)==6) {SendUserData(hCON_IN,&buffer,bSize);};
}
}else{
MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
};
IONTerminate(hCON_IN);
IONDisconnect(hCON_OUT);
CloseIONHandle(hCON_IN);
CloseIONHandle(hCON_OUT);
FreeConsole();
return 0;
}
Пусть интерфейс и неказист и прост, но это уже кое-что не оторванное от жизни.
Скачать пример
Часть 5. А поговорить? Попробуем реализовать простую звонику за NAT
Притянем за уши потребность — пусть нам нужно не много и не мало а позвонить другу в деревню за NAT.
Heredes реализует передачу PCM аудио почти так же просто как и пользовательские данные.
//поговорить за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
int main(void)
{
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
CHAR SecKey[8]; //8-ми байтный массив с ключем шифрования
DWORD Valid = 0;
DWORD Id = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
HANDLE hCON_OUT=CreateIONHandle();
IONSetAudioParam(hCON_OUT,3,"aud_in.wav","aud_sp.wav",NULL);
IONSetAudioParam(hCON_IN,3,"aud_in.wav","aud_sp.wav",NULL);
if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE){
IONStartAudioStream(hCON_OUT,11025);
HANDLE hEv=CreateEventA(NULL,1,NULL,NULL);
WaitForSingleObject(hEv,60000);
CloseHandle(hEv);
}else{
MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
};
IONStopAudioStream(hCON_IN);
IONStopAudioStream(hCON_OUT);
IONTerminate(hCON_IN);
IONDisconnect(hCON_OUT);
CloseIONHandle(hCON_IN);
CloseIONHandle(hCON_OUT);
return 0;
}
Скачать пример
Часть 6. От разговоров к администрированию или CMD over NAT
Еще один относительно быстро реализуемый пример это командная строка за NAT или удаленное перенаправление ввода/вывода. Приступим?
//CMD за NAT
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
CHAR buffer[0x3E0]; //максимальный размер блока пользовательских данных 0х3Е0
HANDLE hOutput;
HANDLE outpipe;
HANDLE inpipe;
HANDLE hEv;
HANDLE hCON_IN;
HANDLE hCON_OUT;
CBUDATA __stdcall UserDataProc(HANDLE hConn, LPVOID pAddrUserData, int datSize)
{
DWORD cRcv=1;
if (IONGetStatus(hCON_IN)==6){
SendCommandLine(outpipe,pAddrUserData);
WaitForSingleObject(hEv,2000);
while(cRcv!=0){
PeekNamedPipe(inpipe,NULL,NULL,NULL,&cRcv,NULL);
if (cRcv!=0){
ReadFile(inpipe,&buffer,cRcv,&cRcv,NULL);
}
SendUserData(hCON_IN,&buffer,cRcv);
}
};
if (IONGetStatus(hCON_OUT)==6){
WriteConsoleA(hOutput,pAddrUserData,datSize,&cRcv,NULL);
};
DWORD inSize;
WriteConsoleA(hOutput,pAddrUserData, datSize, &inSize, NULL);
return 0;
}
int main(void)
{
HANDLE hInCons;
HANDLE hOutCons;
hEv=CreateEventA(NULL,1,NULL,NULL);
StartHiddenConsoleProcess("cmd.exe",&outpipe, &inpipe, &hOutCons, &hInCons);
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
DWORD bSize=0;
CHAR SecKey[8]; //8-ми байтный массив с ключем шифрования
DWORD Valid = 0;
DWORD Id = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
hCON_IN=IONWaitConnection(&Valid, &Id, (CBUDATA) &UserDataProc);
hCON_OUT=CreateIONHandle();
if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, \
NULL, NULL, (CBUDATA) &UserDataProc)==TRUE){
AllocConsole();
HANDLE hInput=GetStdHandle(-10);
hOutput=GetStdHandle(-11);
WriteConsoleA(hOutput,"REMOTE CMD >",12,&bSize,NULL);
while (bSize!=-1){
ReadConsoleA(hInput,&buffer,0x3E0,&bSize,NULL);
SendUserData(hCON_OUT,&buffer,bSize);
}
FreeConsole();
}else{
MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
};
IONTerminate(hCON_IN);
IONDisconnect(hCON_OUT);
CloseIONHandle(hCON_IN);
CloseIONHandle(hCON_OUT);
return 0;
}
Из новенького и интересненького здесь функции StartHiddenConsoleProcess и SendCommandLine. Для деталей смотрите документацию (ссылки внизу).
Скачать пример
Часть 7. Займемся фотографией. Сфоткаем часть экрана удаленного рабочего стола
Вот мы и приблизились к названию библиотеки и, собственно, к чему все шло до этого. Удаленный рабочий стол без головы. Все слышали про безголовые хромы, проекты вроде селениум, но в памяти не всплывает всадник безголовы — Бил в виде Windows отрисованный на виртуальном DC.
Библиотека так же содержит функционал имитации действий мышей и клавиатур на удаленном ПК, но в данном примере мы ограничимся отрисовкой на виртуальном DC рабочего стола удаленной машины. После чего сохраним содержимое DC в BMP-файл.
Со времени выхода первой статьи кое-что изменилось. Теперь мы все же заморачиваемся с указанием не только координат и размера пробрасываемого прямоугольника, но и указанием DC с которого мы срисовываем. Опустив ностальгические размышления о том, как мы докатились до обезглавливания Windows перейдем к делу.
//безголовый скрин
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
int main(void)
{
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
CHAR SecKey[8]; //8-ми байтный массив с ключем шифрования
DWORD Valid = 0;
DWORD Id = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
HDC hCDC;
HDC hDC=GetDC(NULL);
HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
HANDLE hCON_OUT=CreateIONHandle();
SetINVISTParam(hCON_IN,hDC,64, 64, 256, 256,NULL);//установим параметры прямоугольника
//разрешенного для отправки по сети
if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE)
{
hCDC=CreateCompatibleDC(hDC);
StartRemoteINVIST(hCON_OUT,hCDC,512, 512, 1); //размеры изображения
//я решил увеличить,
//но можно было оставить и оригинальные или напротив уменьшить
for (int i=0; i<3; i++){GetRemoteINVISTService(hCON_OUT);}; //получаю видео из 3х кадра
//из за специфики кодека
int sB=SaveINVISTtoBPM(hCON_OUT,"screen.bmp");
}else{
MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
};
DeleteDC(hCDC);
IONTerminate(hCON_IN);
IONDisconnect(hCON_OUT);
CloseIONHandle(hCON_IN);
CloseIONHandle(hCON_OUT);
return 0;
}
В данном примере я получил несколько кадров для будущего битмепа. Вы можете получить 1,2 и сделать выводы из того что выйдет — лучше один раз пощупать чем 10 раз посмотреть.
Скачать пример
Часть 8. И в заключение статьи — напишем свой маленький TeamViewer.
Графические приложения для удаленного управления Windows посредством еще более графического интерфейса — прочно засели в быту. Попробуем реализовать этот функционал в нашем маленьком приложении RDP over NAT
//свой маленький TeamViewer
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "C:\\HEREDES\\heredes.lib")
#include <windows.h>
#include <C:\HEREDES\heredes.h>
HANDLE hEv;
WNDPROC __stdcall ProcClose(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
SetEvent(hEv);
return 0;
}
int main(void)
{
hEv=CreateEventA(NULL,1,NULL,NULL);
InitIONLibrary(); //инициализация библиотек и интерфейсов HEREDES
CHAR SecKey[8]; //8-ми байтный массив с ключем шифрования
DWORD Valid = 0;
DWORD Id = 0;
RegIONId(&Valid, &Id); //регистрация нового пользователя
HDC hCDC;
HDC hDC=GetDC(NULL);
HANDLE hCON_IN=IONWaitConnection(&Valid, &Id, NULL);
HANDLE hCON_OUT=CreateIONHandle();
SetINVISTParam(hCON_IN,hDC,64, 64, GetSystemMetrics(0), GetSystemMetrics(1),NULL); //установим параметры прямоугольника
if (IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)==TRUE)
{
hCDC=CreateCompatibleDC(hDC);
StartRemoteINVIST(hCON_OUT,hCDC,512, 512, 1); //размеры изображения я решил увеличить,
//но можно было оставить и оригинальные или напротив уменьшить
HWND hWin;
CreateINPRT(hCON_OUT, 64, 32, 512, 300, 0x00CF0000, NULL, &hWin, 1, (WNDPROC) ProcClose);
WaitForSingleObject(hEv,-1);
}else{
MessageBoxA(NULL,"ошибка соединения","состояние подключения", 48);
};
CloseHandle(hEv);
IONTerminate(hCON_IN);
IONDisconnect(hCON_OUT);
CloseIONHandle(hCON_IN);
CloseIONHandle(hCON_OUT);
return 0;
}
Скачать пример
В данном случае мы познакомились с функцией CreateINPRT — это по сути встроенный интерактивный плейер реального времени. Этот же пример можно было реализовать посредством отрисовки на DC какого либо окна и использовать функции передачи мыши и клавиатуры библиотеки Heredes, но так, по моему, даже удобнее.
Ссылки: на проект, скачать архив, документация.
Комментарии (14)
MGSpace
31.08.2021 08:29В примере 6 используется функция StartHiddenConsoleProcess . исходя из того что она вызывается до установки коннекта, есть подозрения что это запуск консоли локально. Это так? если да, то есть ли удаленный вариант запуска консоли? в документации не нашел. спасибо.
Brodilla Автор
31.08.2021 08:49Да, на данный момент процесс запускается по ряду причин только локально, более того, данная функция ориентирована именно на консольные приложения и перенаправление ввода/вывода консоли. Хуже того - несмотря на то что консольное приложение запускается локально, его завершение работы управляется только удаленно.
Когда библиотека перейдет из бетты в версию, мы скорее всего еще раз пересмотрим работу с консольными приложениями запущенными в фоновом режиме. На данный момент не до конца понятно общественное мнение и предпочтительное направление развития.
Kotofay
31.08.2021 13:59Пример собранный с вашей библиотекой валится с исключением в IONConnectToId.
MGSpace
31.08.2021 16:00у меня тоже была такая проблема. потом разобрался.
IONConnectToId(hCON_OUT, NULL, &Valid, &Id, &SecKey, NULL, NULL, NULL)
все кроме hCON_OUT - указатели на переменные. при том SecKey это указатель на 8 байтный массив. я пробовал поставить вместо него NULL - валится, вместо других указателей на переменные ставить переменные - тоже валится.
а в остальном, у меня заработало
MGSpace
31.08.2021 16:07хотя в документации у авторов расхождение с примерами - пришел импирическим путем рассматривая примеры. будем надеяться исправят доки
Brodilla Автор
31.08.2021 16:32Спасибо за ваш ответ.
Kotofay
31.08.2021 17:12В указанном примере внутри IONConnectToId первый же вызов CreateThread некорректный -- третий параметр lpStartAddress равен нулю.
push ebx ; lpThreadId
push ebx ; dwCreationFlags
push edi ; lpParameter
mov eax, dword_100070BD
push dword ptr [eax] ; lpStartAddress
push ebx ; dwStackSize
push ebx ; lpThreadAttributes
call ds:CreateThread
Brodilla Автор
31.08.2021 21:42Heredes состоит из двух DLL. Предполагалось, что один будет заведовать графическим интерфейсом, а другой функционалом без GUI. На данный момент это не так и использование отдельно heredes.dll невозможно. Ваша ошибка относится к случаю, когда не удалось зарегистрировать необходимые классы окон или загрузить gui_her.dll. Проследите что бы он был так же в каталоге с программой.
Kotofay
01.09.2021 00:14Да, всё заработало. NAT действительно пробивается.
Нужно работать над API библиотеки, то что есть сейчас совершенно не годится.
Brodilla Автор
01.09.2021 00:36Спасибо за тест.
Мы знаем о том, что не достигнут предел идеала в том что есть, но будем благодарны за любые пожелания о желаемом функционале.
Brodilla Автор
31.08.2021 16:21Спасибо!
Да, в документации была допущена неточность.
Исправлена. https://brodilla.com/ru/heredes/about#IONConnectToId
Будем признательны за любые указания на наши недостатки.
MGSpace
31.08.2021 16:36было б удобна не только отправка файла а загрузка инициированная клиентом. содержимое каталога то консоль показывает и как то можно в фрновом режиме дерево каталогов составлять, хотя и не удобно..
а вот инициировать загрузку с удаленного ПК.. или функция фонового режима для передачи файлов не мешало бы. первый пример крут своей краткостью но вот в обратную сторону он.. ну не годится он для того что б клиент с сервера запросил, а сервер отдал.
возьмите пожалуйста на карандаш/на голосование или как там учитываются пожелания
netricks
А как это работает внутри? Как heredes конектится к машине за NAT?
Brodilla Автор
Старый добрый stun.
Каждый пользователь имеет свой идентификатор, получить который можно вызовом RegIONId.
Приложение, которое вызывает WaitIONConnection регулярно уведомляет stun-сервер о том, что ожидает подключений, указывая свой идентификатор.
Вызов IONConnectToId инициирует появление окна, в котором можно ввести идентификатор сервера.
Далее клиент запрашивает stun: "а где ж сидит сервер с таким ID?" Серверу и клиенту в ответ на такой запрос клиента отправляются данные для прямого подключения.
Для удобства не рекомендуется вызывать RegIONId каждый раз, а получив идентификатор сохранить его. Тогда не придется гадать какой Id у клиента и у сервера, а просто его в дальнейшем использовать.
Пример 2 наглядно демонстрирует различия между кодом клиента и кодом сервера. А в примере 3 - возможный, но не обязательный каркас (клиент и сервер в одном приложении). Все остальные примеры используют именно этот каркас в основе.
Обратите внимание, что мы не участвуем в дальнейшей передаче данных - все идет р2р, мы просто соединяем. А в случае невозможности прямого обмена данными функция IONConnectToId вернет 0 и на этом все закончится.