Pull to refresh

Apache, fastcgi и c++: «Hello, world»

Reading time 6 min
Views 41K
img
Писать web-приложения на C/C++ дело неблагодарное. Многие говорят, что это полное безумие, когда есть PHP и Perl. И я с ними согласен. Это очень просто написать сайт на PHP(особенно используя фреймворки вроде Zend Framework).
Но..(всегда есть какое-то «но»).
Давайте не будем забывать, что простота использования складывается не только из простого синтаксиса. Учитывается множество параметров. И одним из весомых параметров является наличие статей «Get started with ...» с примерами «hello, world»-программ. Я собираюсь добавить немного простоты написанию fastcgi на C/C++. И если прочитав эту статью хоть один человек скажет «А это не так уж и сложно», то я буду считать свою миссию выполненной.

Чтобы пройти весь путь от пустого исходника до надписи на экране браузера, нам придется настроить веб-сервер( в нашем случае Apache), установить на него mod_fastcgi, выбрать библиотеку libfcgi и наконец написать «Hello, world»-программу.

Вступление: FastCGI


О том что такое fastcgi можно прочитать здесь. Если говорить коротко, то это CGI-программа обрабатывающая запросы в цикле. Её преимущество над обычной CGI-программой заключается в что она запускается один раз для обработки множества запросов.

Веб-сервер


Для работы подойдет любой веб-сервер поддерживающий fastcgi интерфейс.
Так сложилось, что все мои попытки взаимодействия с веб проводились с использованием веб-сервера Apache. Выбор его для этой статьи обусловлен скорее его наличием и работой на нем других проектов, чем какими-то особенными характеристиками.

Возможные альтернативы:
Nginx и Lighttpd имеют «родную» поддержку интерфейса fastcgi и их использование более предпочтительно на «продакшн»-серверах. Можно также использовать MS IIS.

Mod_fastcgi, mod_fcgid


Мне известно два модуля при помощи которых осуществляется поддержка fastcgi-интерфейса в апаче, это mod_fastcgi и mod_fcgid.
Mod_fastcgi разрабатывается компанией Open Market c 1997года. Последняя версия 2.4.6 была обновлена 13го ноября 2007 и, как уверяют авторы, является очень стабильной.
Mod_fcgi, судя по домену, разрабатывается китайскими программистами. Последняя версия 2.2 датирована 31июля 2007. Отличительными особенностями от mod_fastcgi являются: новая модель управления fastcgi-программами, обнаружение ошибок в работе fastcgi-программ. Модуль имеет бинарную совместимость и поэтому перекомпилировать программы, работающие под mod_fastсgi нет необходимости.
Используя development kit с fastcgi.com для разработки программ, я решил, что более уместно будет использовать mod_fastcgi, т.к. они используют общую библиотеку libfcgi.

Для подключения модуля mod_fastcgi необходимо добавить в httpd.conf:
LoadModule fastcgi_module modules/mod_fastcgi.so
AddHandler fastcgi-script .fcg .fcgi .exe


Типы запуска fastcgi-программ


Используя mod_fastcgi можно запускать программы тремя различными способами: динамически, статически и удаленно.

Динамический способ запуска: В момент начала работы apache создает только process manager(PM), ожидающий входящих запросов. Как только первый запрос получен, process manager создает экземпляр программы для его обработки. В зависимости от настроек, после обработки запроса программа может быть завершена PM’ом, либо может быть использована для обработки последующих запросов. С помощью настроек можно задавать множество параметров создаваемого пула приложений, такие как минимальный и максимальный размер, время жизни приложений, максимальный размер очереди запросов и другие.
Директива: FastCgiConfig option [option ...]

Статический способ запуска: В момент начала работы apache создает PM, который в свою очередь создает заданное количество экземпляров программы для обработки входящих запросов.
Директива: FastCgiServer filename [option ...]

Удаленный способа запуска: Приложение запускается независимо от apache и PM. PM выступает в роли proxy.
Директива: FastCgiExternalServer filename -host hostname:port [option ...]
FastCgiExternalServer filename -socket filename [option ...]


Методы взаимодействия:


  • Stdin
  • Unix domain socket / named pipe
  • TCP Socket

Stdin: Используется при динамическом способе запуска fastcgi-программ. Взаимодействие происходит через Standard in file descriptor.

Unix domain socket / Named pipe: Может быть использован, как при статическом так и при удаленном способе запуска fastcgi-программ. При статическом способе socket создается process manager’ом, при удаленном способе socket должен быть создан fastcgi-программой. Чтобы использовать данный способ необходимо задать параметр –socket имя_сокета.

TCP Socket: Может быть использован также как и Unix domain socket / named pipe, как при статическом так и при удаленном способе запуска fastcgi-программ. Для использования в статическом режиме необходимо задать параметр -port номер_tcp_порта. Для использования в удаленном режиме параметр -host имя_хоста:номер_tcp_порта.

Меня интересует прежде всего работа с tcp socket'ом и удаленным способом запуска fastcgi-программы, потому что это дает совместимость работы с другими веб-серверами, а также предоставляет более простую возможность отладки.

Fastcgi libraries


Не так уж и много существует библиотек помогающих создавать fastcgi-программы на C/C++. Наиболее популярна libfcgi.lib, которая поставляется в составе development kit от fastcgi.com. Библиотека, честно сказать, предоставляет небогатый функционал для работы.
Существует также Fastcgi++ библиотека классов на С++.
Так как это моя первая fastcgi-программа, то я буду использовать старую, проверенную библиотеку libfcgi.lib.

Hello_world.fcgi


Программа использует для коммуникации TCP Socket, открывая порт номер 9000. В браузере выводится строка «Fastcgi: Hello, world».
Используемые функции:
int FCGX_Init(void);
— Инициализация библиотеки FCGX
int FCGX_OpenSocket(const char *path, int backlog);
— Открывает слушающий сокет (Параметры: path – имя сокета, backlog – глубина стека запросов).
int FCGX_InitRequest(FCGX_Request *request, int sock, int flags);
— Инициализируем структуру запроса для использования внутри FCGX_ Accept_r (Параметры: request – указатель на структуру запроса, sock – слушающий сокет используемый совместно с request, flags – флаг запроса (доступные флаги: FCGI_FAIL_ACCEPT_ON_INTR – не вызывать повторно accept при разрыве).
int FCGX_Accept_r(FCGX_Request *request);
— Получает новый запрос на обработку.

Полный текст программы:
#include <string><br/>
#include "fcgi_stdio.h"<br/>
#include <stdlib.h><br/>
#pragma comment(lib"libfcgi.lib")<br/>
<br/>
int main(int argc, char* const argv[] )<br/>
{<br/>
    std::string port=
":9000";        //Задаем номер порта TCP<br/>
    int  listenQueueBacklog = 400;    //Глубина стека запросов<br/>
    FCGX_Stream *in, *out, *err;<br/>
    FCGX_ParamArray envp;<br/>
<br/>
<br/>
    
if(FCGX_Init())    exit(1); //Инициализируем библиотеку перед работой.<br/>
<br/>
    int  listen_socket = FCGX_OpenSocket(port.c_str(), listenQueueBacklog); //Открываем новый слушающий сокет<br/>
    if(listen_socket < 0)    exit(1);<br/>
<br/>
    FCGX_Request request;<br/>
    
if(FCGX_InitRequest(&request,  listen_socket, 0)) exit(1); //Инициализируем структуру запроса<br/>
<br/>
    while(FCGX_Accept_r(&request) == 0)<br/>
    {<br/>
        FCGX_FPrintF(request.out,
"Content-type: text/html\r\n\r\n<TITLE>fastcgi</TITLE>\n<H1>Fastcgi: Hello world.</H1>\n");<br/>
<br/>
        FCGX_Finish_r(&request);
//Завершаем запрос<br/>
    }<br/>
<br/>
    
return 0;<br/>
}<br/>



Vhosts.conf


Кусочек файла настройки vhost.conf отвечающий за helloworld.local:
NameVirtualHost 127.0.0.1:80
<VirtualHost 127.0.0.1:80>
  ServerAdmin mail@localhost 
  DocumentRoot «C:/Apache2/cgi-bin»  
  ServerName «helloworld.local»
 
  <Directory «C:/Apache2/cgi-bin»>
    Options Indexes FollowSymLinks MultiViews ExecCGI
    AllowOverride all
        Order Deny,Allow
Deny from all
Allow from 127.0.0.1
  </Directory>
 
  <Files hello_world.exe>
     SetHandler fastcgi-script
  </Files>
 
  FastCgiExternalServer C:/Apache2/cgi-bin/hello_world.exe -host 127.0.0.1:9000
</VirtualHost>

В папке «C:/Apache2/cgi-bin» у меня находится файл .htaccess, направляющий все запросы к helloworld.local на hello_world.exe.

Окончание


Ну вот и все, теперь у меня в браузере гордо высвечивается фраза «Fastcgi: Hello, world».
Tags:
Hubs:
+76
Comments 114
Comments Comments 114

Articles