Программирование WinInet C++. Часть 2

Целью создания системы явилась потребность в удаленном управлении и администрировании домашним компьютером, получении и обмене информации с ним, при помощи веб браузера используемого как в компьютере, так и в сотовом телефоне.

Принцип работы системы заключается в следующем, на домашнем компьютере запущенна программа(«wr_admin.exe»), которая через определенные промежутки времени, производить чтение конфигурационного файла («cmd.txt»), в защищенной директории веб сервера. При появлении в данном файле управляющего кода, в данной реализации это просто цифры 0 и 1 (ноль означает ждать команды, единица выдать IP адреса всех сетевых интерфейсов установленных на домашнем компьютере). Программа получает необходимые адреса интерфейсов и при помощи функций WinInet передает их в информационный файл(«info.txt»), информация из которого в последующем выводится в панели управления системой, открытой в веб браузере. Более наглядно данную схему взаимодействия можно представить на рисунке:
Программирование WinInet C++. Часть 2
Для реализации идеи, как и в прошлом примере, создается директория защищенная паролем на чтение, содержащая в себе два конфигурационных файла: .htaccess и .htpasswd. Содержимое файла .htaccess выглядеть следующим образом:

RemoveHandler .html .htm
AddType application/x-httpd-php .php .htm .html .phtml
AuthType Basic
AuthName 'Authorization panel'
AuthUserFile /home/******/blaginru/www/wr_admin/.htpasswd
Require valid-user

Обратите внимание на первые две строки файла, помеченные курсивным шрифтом, это специальные команды настройки веб сервера Apache, которые дают возможность выполнения PHP скриптов внутри обычного html файла. Файл .htpasswd как и в прошлом примере содержит в себе имя пользователя и хэш пароля:

admin:Ht3WXRz2HYe52

Хочу обратить ваше внимание, что именно эти имя пользователя и пароль используются для авторизации как пользователя, при запуске панели администрирования, так и программы «wr_admin.exe» для обмена информацией с веб сервером.

Следующим важными частями системы являются два PHP скрипта «wr_admin.php» и «wr_admin_info.php», которые отвечают за запись информации и управляющих кодов в файлы «cmd.txt» и «info.txt», как видите ниже, эти скрипты не сильно отличаются друг от друга, для наглядности курсивом отмечены основные их отличия:

//wr_admin.php
<?
$handle=fopen("cmd.txt","w") or die("Error open file");
flock($handle,LOCK_EX);
if (fwrite($handle, "$mess") === FALSE)
{
        echo "Error write file";
}
else
{
        fflush($handle);
        echo("<script>location.href='index.html'</script>");
}
 
flock($handle,LOCK_UN);
fclose($handle);
exit();
?>
// wr_admin_info.php
<?
$handle=fopen("info.txt","w") or die("Error open file");
flock($handle,LOCK_EX);
if (fwrite($handle, "$mess") === FALSE)
{
        echo "Error write file";
}
else
{
        fflush($handle);
        echo("<script>location.href='index.html'</script>");
}
 
flock($handle,LOCK_UN);
fclose($handle);
exit();
?>

Следующим звеном системы является панель администрирования, которая выполнена в виде HTML файла, как раз именно ее мы будем загружать на удаленном компьютере или в веб браузере телефона, для управления домашним компьютером, ниже приведен кусок файла отвечающий за передачу управляющего кода в файл «cmd.txt» и вывод информации из файла «info.txt»:

// Отправка управляющего кода:
<form action="wr_admin.php">
<select name=mess size=1>
<option value=1 selected>Узнать IP адрес</option>
</select>
<button type="submit">Отправить команду</button>
</form>
//Чтение и вывод информации:
<?php
$filename = "info.txt";
$handle = fopen($filename, "r");
$contents = fread($handle, filesize($filename));
echo $contents;
fclose($handle);
?>

Теперь же пришло время описать последнюю, но немаловажную часть системы, программу «wr_admin.exe» которая как было сказано ранее и представлено на рисунке, служить для проверки файла «cmd.txt» на наличие управляющего кода и отправки информации в файл «info.txt». Для создания программы использовалась среда разработки MS Visual C++ 6.0, при помощи «MFC AppWizard(exe)» сгенерирован проект на основе диалога. Для возможности чтения файла «cmd.txt», был добавлен дополнительный поток, так как при выполнения чтения в контексте основного потока приложения, графическая часть программы начинала зависать и не реагировать на входящие сообщения.
Прототип функции потока выглядит следующим образом:

UINT ThreadProc(LPVOID param);

Реализация функции потока:

UINT ThreadProc(LPVOID param)  //Создание потоковой функции
{
        //Получение сылки на диалог для возможности изменения элементов управления
        CWr_adminDlg * dlg = (CWr_adminDlg*)param;
 
    while(!bThreadStop)
    {
                CHttpConnection * pConnect;
                CInternetSession iSession;
                CHttpFile * pFile;
 
                CString m_sTemp;
                        
                pConnect = iSession.GetHttpConnection("www.blagin.ru",80,"admin","Password");
                if(pConnect)
                {
                        //Получаем код управления
                        pFile = pConnect->OpenRequest("GET",(LPCSTR)"/wr_admin/cmd.txt","www.blagin.ru");
                        pFile->SendRequest(NULL);
                        
                        if(pFile)
                        {
                                while(pFile->ReadString(m_sTemp))
                                {
                                        dlg->SetTextEdit(m_sTemp);
                                        if(m_sTemp == "1")//Передать IP адрес
                                        {
                                                //незабываем обнулять командный файл
                                                dlg->SendCode("0");
                                                dlg->SendData(1);
                                        }
                                }
                        }
                }else{dlg->SetTextEdit("GetHttpConnection error");}
                iSession.Close();
                pFile->Close();
                Sleep(1000);//останавливаем поток на определенное время
    }
return 0;
}

Также в программе была предусмотрена функция обнуления командного файла, для избегания зацикливания передачи информации, реализация функции представлена ниже:

//Функция отправки кода в файл cmd.txt чтобы не зациклить выполнение команды(Обнуление)
void CWr_adminDlg::SendCode(CString m_code)
{
        CHttpConnection * pConnect;
        CInternetSession iSession;
        CHttpFile * pFile;
        CString m_sTemp;
        pConnect = iSession.GetHttpConnection("www.blagin.ru",80,"admin","password");
        if(pConnect)
        {                       
                m_sTemp = "/wr_admin/wr_admin.php?mess="+m_code;
                pFile = pConnect->OpenRequest("GET",m_sTemp,"www.blagin.ru");
                pFile->SendRequest(NULL);
                
        }else{SetTextEdit("GetHttpConnection error");}
 
        iSession.Close();
        pFile->Close();
}

Основная функция передачи информации приложения:

//Передача данных в файл info.txt
void CWr_adminDlg::SendData(int iCodeData)
{
        CString m_sTemp;
//Передать IP адреса компьютера///////////////////////
        if(iCodeData == 1)
        {
                        CHttpConnection * pConnect;
                        CInternetSession iSession;
                        CHttpFile * pFile;
                        pConnect = iSession.GetHttpConnection("www.blagin.ru",80,"admin","password");
 
                        if(pConnect)
                        {
                                m_sTemp = "/wr_admin/wr_admin_info.php?mess="+GetIP();
                                pFile = pConnect->OpenRequest("GET",m_sTemp,"www.blagin.ru");
                                pFile->SendRequest(NULL);
                        }else{SetTextEdit("GetHttpConnection error");}
                        iSession.Close();
                        pFile->Close();
                
        }
}

Так же приведу пример получения IP адресов установленных сетевых интерфейсов в компьютере, пример взять с сайта «Первые шаги», немного изменен и дополнен:

//Получение IP адреса компьютера
CString CWr_adminDlg::GetIP()
{
        CString m_ipstring;
        //Добавление времени выполнения
         CTime ct= CTime::GetCurrentTime();
         m_ipstring.Format("%d:%d:%d",ct.GetHour(),ct.GetMinute(),ct.GetSecond());
         m_ipstring += "- Время выполения <br>";
        ///////////////////////////////
        WSADATA wsaData;
    if (!WSAStartup(0x0202, &wsaData))
    {
        char chInfo[64];
        if (!gethostname(chInfo,sizeof(chInfo)))
        {
            hostent * sh;
            sh = gethostbyname((char*)&chInfo);
            if(sh != NULL)
            {
                int   nAdapter = 0;
                while (sh->h_addr_list[nAdapter])
                {
                    struct   sockaddr_in   adr;
                    memcpy(&adr.sin_addr,sh->h_addr_list[nAdapter],sh->h_length);
                    m_ipstring += "IP:  ";
                    m_ipstring += inet_ntoa(adr.sin_addr);
                    m_ipstring += "<br>";
                   nAdapter++;
                }
            }
        }else SetTextEdit("gethostname error");
    }else     SetTextEdit("WSAStartup error");
 
    WSACleanup();
return m_ipstring;
}

Система не идеальна и многое можно было бы сделать по-другому, например вместо двух PHP скриптов использовать один, так же и с файлами, содержащими информацию и управляющие коды, панель администрирования можно сделать полностью на PHP тогда не пришлось бы добавлять дополнительные строки в конфигурационный файл веб сервера. Хотя для понимания функционирования системы, такое разделение удобно и оно работает, чего и требуется от системы. Надеюсь, вам понравилась идея и ее реализация, спасибо, что прочли статью.