C/C++. Read file to the buffer

#include <iostream>
#include <fstream>

using namespace std;

void main(void) {
   
    int length;
    char* buffer;
   
    ifstream myfile;
    myfile.open("C:\\test.txt", ios::binary);
   
    //get length of file
    myfile.seekg(0, ios::end);
    length = myfile.tellg();
    myfile.seekg(0, ios::beg);
   
    //allocate memory
    buffer = new char[length];
   
    //read data as a block to buffer
    myfile.read(buffer, length);
    myfile.close();
   
    cout.write(buffer, length);
   
    delete[] buffer;
}

Особая конструкция для определения размера файла (в байтах):

int length;
long sizeFile, begin, end;
   
// to write all recived data from buffer in buffer.txt
ifstream toFile("buffer.txt");

// size of buffer.txt;
begin = toFile.tellg();
toFile.seekg(0, ios::end);
end = toFile.tellg();
sizeFile = (end-begin);

printf("buffer.txt size is %d bytes\n", sizeFile);


C/C++. Сетевое программирование. Winsock. Client IP address

Add this code to your project.

...
// Структура для определения ip адреса клиента 
sockaddr_in name;
int name_size = sizeof(name);
// Обязательное обнуление элементов структуры
ZeroMemory(&name, sizeof(name));
...
// Получаем данные о клиенте, которые заполняют объявленную выше структуру
getsockname(ClientSocket, (sockaddr*)&name, &name_size);
// Выводим ip адрес клиента. Для получения адреса в виде 32 битового числа (4ех 8ми битных
// октетов) используется метод inet_ntoa()
printf("Client IP address is:%s\n", inet_ntoa((in_addr)name.sin_addr));
...



C/C++. Сетевое программирование. Создание веб-сервера. Часть 2

#undef UNICODE

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")

// Размер буфера для приема данных веб-сервером (http-запросы)
#define DEFAULT_BUFLEN 512
// Зарезирвированный за HTTP протоколом номер порта
#define DEFAULT_PORT "80"


int __cdecl main(void)
{
    // Для передачи Status-Line (Статус веб-сервера)
    char status[]="HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\n\r\n";
    // Для передачи message-body. В данном случае - данные в xml-формате
    char xml[]="<?xml version=\"1.0\" encoding=\"windows-1251\"?>\n<test>test</test>";

    WSADATA wsaData;
    // Для хранения количества принятых данных (байты)
    int iResult;
    // Инициализируем соответствующие сокеты
    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;

    // Инициализируем соответствующую структуру для работы веб-сервера
    struct addrinfo *result = NULL;
    struct addrinfo hints;
   
    // Инициализируем структуру для последующего определения обращающихся на веб-сервер клиентов
    sockaddr_in name;
    int name_size = sizeof(name);
    // Обязательное обнуление элементов структуры
    ZeroMemory(&name, sizeof(name));

    // Для хранения количества оправленных данных (байты)
    int iSendResult;
    // Буфер для приема данных веб-сервером (http-запросы)
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
   
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }
   
    // Обязательное обнуление элементов структуры
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // Setup the TCP listening socket
    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Определяем IP-адрес клиента, постучившегося на веб-сервер
    getsockname(ClientSocket, (sockaddr*)&name, &name_size);
    // Выводим на консоль сервера
    printf("Client IP:%s\n", inet_ntoa((in_addr)name.sin_addr));

    // No longer need server socket
    closesocket(ListenSocket);

    // Receive until the peer shuts down the connection
    // Принимаем данные
    iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);

    if (iResult > 0) {
        printf("Bytes received: %d\n", iResult);
        printf ("%s\n", recvbuf);
        printf ("%s\n", "Insert for debug...");
       
        //Сначало передается http-ответ браузеру и только потом соответствующий content
        //Обязательно sizeof(status) - 1, для ограничения передачи сокету клиента символа конца строки NULL
        send(ClientSocket, status, sizeof(status) - 1, 0 );
        printf("%s\n", status);
       
        //Обязательно sizeof(xml) - 1, для ограничения передачи сокету клиента символа конца строки NULL
        iSendResult = send(ClientSocket, xml, sizeof(xml) - 1, 0 );
        printf("%s\n", xml);
       
        if (iSendResult == SOCKET_ERROR) {
            printf("send failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return 1;
        }
       
        printf("Bytes sent: %d\n", iSendResult);
       
    }
    else if (iResult == 0)
        printf("Connection closing...\n");
    else  {
        printf("recv failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }


    // shutdown the connection since we're done
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }

    // cleanup
    closesocket(ClientSocket);

    WSACleanup();

    return 0;
}

Данный код представляет собой простейший веб-сервер. Данный листинг можно скачать по ссылке - download. Принимать данные он принимает, но без какой-либо обработки. В ответ он оправляет свое статусное состояние (Status-Line) и message-body, в виде данных xml-формата (генерирует на клиентской стороне xml-страничку). По аналогии можно отправлять и html-страницы. Модель конечно примитивная, но отрываясь от этого можно создать вещь по-круче. Также она не учитывает множественность клиентских обращений на сервер. Тоже решаемо. Нет поддержки скриптовой части.  Правда для себя опробовал (cgi-интерфейс). Работает. Про взаимодействие с переменными окружения вообще молчу. Но все в наших руках. Данную модель я рассматривал только для изучения логики диалога веб-браузеров и веб-серверов. Тестировал на Windows Vista Home Basic (Service Pack 1), Visual C++ 2008 Express, Internet Explorer 8, Firefox 12.
В попытках найти хоть что-то связанное с разработкой своего веб-сервера на C/C++ (под платформу - Win32), потратил кучу времени, но так найти ничего и не смог. Мне твердили, что лучше ознакомиться с "сорсами" Apache или Nginx, но для меня нужна была ясность и простота. Единственное, в дебрях интернета встретил такой ресурс, где-то я его уже упоминал -  "Самый маленький и самый быстрый WEB- сервер для Linux/UNIX/Windows". Там есть хороший "сорс", хоть и заявлено - для Linux/UNIX/Windows, все-же он ориентирован на UNIX. В частности, я тестил его на Linux Ubuntu Server v.12.04 32bit (виртуалка).
Надеюсь, что кому-то все это поможет, пусть и в образовательных целях. Удачи Вам:)

C/C++. Сетевое программирование. Создание веб-сервера. Часть 1

Создание веб - сервера. Громко сказано конечно :) Да и есть ли в этом необходимость, когда уже созданы такие веб - сервера, как, из самых известных:
- Apache и Apache Tomcat (Sun Microsystems);
- разработка Игоря Сысоева - Nginx;
- разработка компании Microsoft - IIS (Internet Information Services).
Но помимо этого есть и альтернативные разработки: Ascet HTTPd, CERN httpd и другие. С таким списком можно ознакомиться на Wiki.

Лично для меня архитектура и логика работы веб - сервера вызывает интерес.
Все мы знаем, что многоликий интернет базируется на работе раскинутых веб - серверов, связанных между собой в глобальную сеть за счет различных сетевых устройств. Например - роутеров, маршрутизаторов, коммутаторов и тому подобное. Опустим технические нюансы. Потребители интернета со своих машин также подключены к этой сети. И через соответствующие сетевые программы, так называемые -  User-agent - браузеры (от англ. browse - проссматривать) просматривают (точнее - запрашивают) веб - странички, которые располагаются на веб - серверах. Помимо содержания веб - страниц, веб - сервер может содержать и скриптовую часть. Мини-экскурс :) Но я пошел дальше.

Как можно разработать свой веб - сервер на C/C++?

Для этого воспользуемся прикладным интерфейсом - Windows Socket API (Winsock).

Прежде, чем приступать к программированию на данном интерфейсе, рассмотрим общие характеристики веб - серверов:
- в простейшем случае используют http - протокол и зарезервированный порт - 80, 8080;
- сервер принимает запросы от браузеров и отправляет им ответы в строго определенном виде. Определение запросов и ответов представлены в специальных документах, так называемым - Internet Request For Comment (RFC), в частности - RFC 2086. Рассмотрим пример диалогов HTTP (более подробно можно ознакомиться на Wiki).

Запрос клиента:
GET /wiki/страница HTTP/1.1
Host: ru.wikipedia.org
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5) Gecko/2008050509
Firefox/3.0b5
Accept: text/html
Connection: close
(пустая строка) 
 
Ответ сервера:
HTTP/1.1 200 OK
Date: Wed, 11 Feb 2009 11:20:59 GMT
Server: Apache
X-Powered-By: PHP/5.2.4-2ubuntu5wm1
Last-Modified: Wed, 11 Feb 2009 11:20:59 GMT
Content-Language: ru
Content-Type: text/html; charset=utf-8
Content-Length: 1234
Connection: close

(далее следует запрошенная страница в HTML) 
 
Отсюда видна структурированность HTTP диалога между клиентами и веб - серверами.
Так как мы рассматриваем разработку серверной стороны, стоит более внимательно
посмотреть на процесс формирования ответа сервера на сторонние запросы. Для
этого приведем схему;
 
 
 
 
 
 





- GET и POST методы передачи данных на сервер;
- скриптовая часть. Для этого организовываются внешние потоки, в которых происходит инициализация внешних скриптов на основе cgi, php, perl и даже bat - файлов;


C/C++. Сетевое программирование. Windows Socket

Что такое Winsock? В свое время для разработки сетевых приложений на операционных системах Berkeley Software Distribution (BSD) UNIX была разработана парадигма сетевых сокетов (Berkeley socket). Сетевой сокет - программный интерфейс обеспечивающий информационный обмен между сетевыми процессами. Данная парадигма  также была подхвачена разработчиками операционной системы Windows компании Microsoft. Так был разработан прикладной интерфейс для сетевого программирования - Windows Sockets 1.1 и в настоящее время - Windows Sockets 2.

Для ознакомления с данным интерфейсом можно воспользоваться технической библиотекой компании Microsoft - msdn Windows Socket 2, либо скачать в off-line режиме отличный (на мой взгляд) FAQ, либо в on-line -  http://tangentsoft.net/wskfaq/. Данный FAQ на английском. Здесь представлены примеры реализации данного интерфейса и есть ответы на различные интересные вопросы.

PHP on Windows. Работа с изображениями

Go to http://www.php.net/downloads.php and download the 'PHP 5.x.x zip package' if you don't allready have it. This package contains the GD-Library for windows. Find php_gd2.dll (or php_gd.dll if you need gif-support, but you will have less good image quality) and put it in your php folder (Usual c:\php). Find in the php.ini in your windows folder:

;extension=php_gd.dll
;extension=php_gd2.dll


Uncomment extension="php_gd2".dll by deleting the ';' in front of it.

Combination Html, Javascript and C/C++. Standalone dinamic application









Мысль. Создание "десктоповых" приложений с помощью сочетания Html, Javascript и C/C++.
Идея изображена выше. Зачем?  

Html - инструмент создания графического пользовательского инструмента (Graphical user interface - GUI).

Javascript - придание динамичности интерфейсу и для взаимодействия с окружением (Ajax).

C/C++ - разработка модулей окружения (функциональная начинка) на основе сетевых сокетов, для операционных систем семейства NT - WinSock.

К тому же такая среда разработки как Visual C++ 2008 Express Edition имеет компонент (Toolbox) - WebBrowser, который может "обернуть" html и javascript файлы в исполняемый exe-файл, а модули внедрить в компонент WebBrowser.  

Кроссдоменный AJAX. In action

В последнее время никак не мог разгадать одну загадку, касающуюся объекта XMLHttpRequest, ну или - XHR. В моем случае на локальном диске располагалась html - страничка, которая при определенном событии (нажатии кнопочки Send) создавала "фоновый" запрос к веб-серверу. Для этого использован асинхронный Javascript (AJAX). Также данная страничка была размещена на веб - сервере в соответствующей корневой директории.

Для тестирования воспользовался нетрадиционным веб - сервером автора Максима Калабзина - Ascet HTTPd (http://ascethttpd.ruall.org/). Связано это с тем, что для меня важно было видеть весь код, дабы при случае можно было самому отлавливать те или иные баги. На текущий момент доступна версия Ascet HTTPd v.1.4. Она написана на C, из скриптовой поддержки - cgi, хотя при желании можно прикрутить и покруче функционал. Развернул данный веб - сервер на виртаулке (Linux Ubuntu Server v.12.04 32bit).

Загадка состояла в том, что  "фоновый" запрос к веб-серверу в свойствах объекта XMLHttpRequest - responseText и responseXML, в Internet Explorer (v.8) возвращались с ожидаемым содержимым, в то время как FireFox (v.11) возвращал либо ничего, либо null. Так происходило только если данный запрос отправлялся с локальной странички. Если же обращение происходило непосредственно к веб - серверу, который подгружал туже страницу, то запрос возвращал в обоих случаях все так, как и полагалось.
Сравним относительные адреса этих страниц:
- локальное расположение file:///C:/index.htm
- на веб - сервере http://127.0.0.1/index.htm
Отсюда видно, что они в своем роде - сайты с разных доменов. Это я клоню к так называемой безопасности браузера FireFox - "Same Origin Policy" (Политика одного источника), то есть каждому сайту своя песочница, чтобы свести к минимуму их взаимодействие. Например об этом написано на сайте Mozilla Developer Network:

Cross-site HTTP requests initiated from within scripts have been subject to well-known restrictions, for well-understood security reasons.  For example HTTP Requests made using the XMLHttpRequest object were subject to the same-origin policy.  In particular, this meant that a web application using XMLHttpRequest could only make HTTP requests to the domain it was loaded from, and not to other domains.  Developers expressed the desire to safely evolve capabilities such as XMLHttpRequest to make cross-site requests, for better, safer mash-ups within web applications.

К тому же каждый запрос анализировался (громко сказано) с помощью плагина FireFox - LiveHTTPHeaders v.017 (http://livehttpheaders.mozdev.org/). Откуда было замечено, что браузер отправляет в сторону веб - сервера http - заголовок "Origin". Который указывает на источник запроса, то есть место, откуда посылается запрос. В случае с локальной страницей - Origin указывал на null. В случае веб - сервера - http://127.0.0.1/index.htm
И снова мысли наводили на "Same Origin Policy". Все точки над "и" расставила статья на хабре - "Кроссдоменный AJAX" (http://habrahabr.ru/post/114432/). Вот ее текст:

На вопрос, как сделать AJAX запрос к другому домену, я всегда отвечал, что никак, и предлагал в качестве альтернативы jsonp, прокси, флеш, фреймы. Но, оказывается, большинство современных браузеров (IE8+, FF3.5+, Chrome 6+ и Safari 4+) вполне поддерживает кроссдоменный XMLHTTPRequest.

С клиентской стороны все остается без изменений. Только теперь браузер не блокирует запрос при отправке, а добавляет к нему заголовок с именем домена, откуда делается запрос: Origin: example.com

Ответ от сервера он так просто назад не пропускает, сервер должен добавить специальный заголовок:
Access-Control-Allow-Origin: *
Вместо звездочки сервер может указать конкретный домен, которому разрешено получить ответ.

Вот такое элегантное решение. Без лишних HTTP запросов, без изменения клиентского API, без нарушения безопасности существующих приложений (ведь подгрузить картинку с другого домена или отправить форму в ифрейм можно было и раньше), и наконец, в отличие от Флеша, с гибкой настройкой прав доступа к индивидуальным страницам.


Как только в ответы веб - сервера было заложено то, что здесь рекомендовано: добавлен специальный заголовок:

Access-Control-Allow-Origin: *

FireFox отобразил то, чего так долго не мог от него добиться. Действительно - элегантное решение. Как следствие данный подход можно реализовать на уровне скриптов.
Например, - в cgi скрипте:

// Some code
printf("Access-Control-Allow-Origin: *\r\n");
printf("\r\n");
// Some code

- в php: 

 // Some code
header("Access-Control-Allow-Origin: *");
// Some code

   
Под конец приведу код той самой html - страницы, которую то и дело тропошил во время решения данной головоломки. Удачи нам в этом нелегком деле :)

<html>
    <head>
        <title>Testing web page...</title>
        <script language="javascript" type="text/javascript">
            function createRequest() {
                var request = null;
                try {
                    // Mozilla, FireFox, Safari, Opera и последние версии IE
                    request = new XMLHttpRequest();
                }     catch (trymicrosoft) {
                    try {
                        // большинство IE
                        request = new ActiveXObject("Msxml2.XMLHTTP");
                    }    catch (othermicrosoft) {
                        try {
                            // для некоторых IE
                            request = new ActiveXObject("Microsoft.XMLHTTP");
                        }    catch (failed) {
                            request = null;
                            }
                        }
                    }  
                // Проверяем на успешность создание объекта request
                if (request == null) {
                    alert("Error creating request object!");
                } else {
                    return request;
                }
            }
      
            function getResponse() {
                var myrequest = createRequest();
                // URL сценарий на сервере
                var url = "http://127.0.0.1";
                url = url + "?dummy=" + new Date().getTime();
                myrequest.open("GET", url, true);
                myrequest.send(null);
                myrequest.onreadystatechange = catchIT(myrequest);              
            }
      
            function catchIT(myrequest) {
              
                if(myrequest.readyState == 0) {
                    alert("0");
                }
                if(myrequest.readyState == 1) {
                    alert("1");
                }
                 if(myrequest.readyState == 2) {
                    alert("2");
                }
                 if(myrequest.readyState == 3) {
                    alert("3");
                }
                if(myrequest.readyState == 4) {
                    alert(myrequest.responseText);
                }              
            }
        </script>
    </head>
    <body>
        <form method="GET" action="#">
            <p id="inname">Type your name:</p>
            <p><input type="text" size="10" name="usname" id="usname" /></p>
            <!-- getResponse() -->
            <p><input value="Send" type="button" onClick="getResponse();"/></p>          
        </form>
    </body>
</html>