Czy C ++ może być używany jako język programowania WWW po stronie serwera? [Zamknięte]

34

Chciałbym zająć się tworzeniem stron internetowych przy użyciu C ++ jako „języka skryptowego” po stronie serwera. Moja infrastruktura serwerowa jest oparta na * nix, więc tworzenie aplikacji internetowych w C ++ na platformie Azure nie ma zastosowania, a C ++ / CLI ASP.NET również nie ma zastosowania.

Niezależnie od starszych aplikacji CGI, czy tworzenie stron internetowych może odbywać się za pomocą C ++?

Scott Davies
źródło
33
Oczywiście jest to możliwe , pytanie brzmi; czy to jest praktyczne ?
Ed S.
Zobacz to pytanie na stackoverflow.com.
kevin cline
24
Można by użyć asemblera jako języka po stronie serwera, gdybyś miał na to ochotę.
Channel72
8
Lub nawet Brainf * ck jeśli ,.są przekierowywane do gniazdka.
dan04
4
Przywołuje to okropne wspomnienia z pierwszego projektu internetowego, w który byłem zaangażowany. Bramy CGI do kodu C. Nadal drżę, kiedy o tym myślę! :-)
Brian Knoblauch,

Odpowiedzi:

56

Absolutnie.

Istnieje nawet kilka ram do ich opracowania, w tym Wt , cppcms , CSP i inne. Główna implementacja FastCGI jest w C i obsługuje bezpośrednio kilka języków , w tym C ++.

Dowolny język programowania, który może analizować ciągi znaków, może być używany w CGI lub serwletu. Dowolny język, który może implementować powiązania z bibliotekami C, może być również użyty do opracowania modułów dla serwerów kompatybilnych z ISAPI lub Apache.

W C ++ nie jest to szczególnie łatwe, a dobre silniki szablonów są nieliczne, ale można to zrobić.

Oczywiście pytanie, czy jest to dobry pomysł, jest zupełnie inną sprawą. :)

Uwaga: główne strony internetowe, takie jak Amazon.com, eBay i Google, używają C ++ do części swojej infrastruktury. Pamiętaj jednak, że Google używa C ++ tylko w systemach o kluczowym znaczeniu dla szybkości, a Amazon.com stosunkowo niedawno zrezygnował z Lisp (co rozgniewało niektórych z ich starszych pracowników :).

Facebook wcześniej skompilował PHP do C ++, ale ich kompilator HipHop (napisany częściowo w C ++) został odtąd zmodyfikowany jako maszyna wirtualna z kodem bajtowym.

greyfade
źródło
2
+1 Za cytowanie różnych ram. Powinieneś dodać, że (bardzo) duże aplikacje internetowe są zasilane przez c ++ (i inne języki): amazon.com, google.com, teraz facebook.com przez hiphop itp.
Klaim
7
@Klaim: To powszechne, ale w żadnym wypadku nie jest to regułą. Architektura Amazon była historycznie oparta na Lisp i dopiero niedawno przepisana w C ++. Architektura Google obejmuje Java, Python i inne prawie tak często jak C ++, wszystkie z różnych powodów. Facebook korzysta teraz tylko z hiphopu, ponieważ odkryli, że PHP się nie skaluje. :)
greyfade
4
Zgadzam się, ale miałem na myśli, że nadal są to dobrze znane przykłady użycia C ++ - do bezpośredniej odpowiedzi na oryginalny tytuł pytania.
Klaim
1
@Johannes Problem ze skalowaniem Facebooka wynika z faktu, że muszą one utrzymywać rząd wielkości większej liczby serwerów niż jest to konieczne, szczególnie ze względu na niską wydajność zoptymalizowanego skryptu PHP. Skalowanie liniowe po prostu nie jest wystarczające dla tak dużej infrastruktury. Pamiętaj jednak, że podejście „nic wspólnego” nie dotyczy wyłącznie PHP. C i C ++ też mogą to zrobić.
greyfade
1
@amar Chodzi o to, że zwrot jest niewielki, z wyjątkiem 0,1% aplikacji, które potrzebują tej surowej wydajności. Możesz obsługiwać w 1/3 czasu w większości innych języków z dobrą obsługą stosów internetowych. Banki, reklamodawcy internetowi itp. Obsługują ogromną skalę bez uciekania się do C ++. Nawet Facebook. Świergot. Przepełnienie stosu. Wszystko to odbywa się w językach wyższego poziomu. Jest tutaj, ale już nie stanie się większością. Prawdopodobnie kiedykolwiek.
Rig
18

Dlaczego nie?

OkCupid serwis randkowy jest tworzony z C ++. Są prawdopodobnie inne przykłady.

Istnieje również inspirowany Qt zestaw narzędzi do tworzenia aplikacji internetowych w C ++ o nazwie Wt .

Vitor Py
źródło
11
„Dlaczego nie ”? Ponieważ o wiele łatwiej jest używać języka, który ma większe wsparcie dla tego rodzaju rzeczy.
Ed S.
5
@Ed S. Jak zauważyłem i greyfade, istnieją ramy do tworzenia aplikacji internetowych w C ++.
Vitor Py
2
Tak, ale czy są one równie łatwe w użyciu, co powszechnie używane frameworki? Szczerze pytam, nie jestem programistą i nigdy ich nie używałem, ale coś mi mówi, że prawdopodobnie nie są tak dojrzałe ani powszechnie używane, jak (na przykład) ich odpowiedniki w ruby ​​/ python / PHP.
Ed S.
3
@EdS .: Ani Ruby, ani Python nie zaczęły od frameworków internetowych. W rzeczywistości pojawienie się ich zajęło dziesięć lat. Ramy są jedynie konsekwencją wystarczającej liczby osób chcących używać języka X dla problemu Y. To samo może się zdarzyć dla C ++. Główne powody, dla których tak się nie stało: C ++ nie jest zarządzany, kompilacja zajmuje wiele lat i ogólnie ma wyższą barierę wejścia.
back2dos
1
@ back2dos: Kto powiedział, że którykolwiek język został opracowany z myślą o Internecie? Na pewno nie. Użyłem terminu „wsparcie”.
Ed S.
11

Jeśli planujesz napisać swoją aplikację internetową w C ++, całkowitym marnotrawstwem byłoby zinterpretowanie jej jako CGI.

Moją sugestią byłoby zbudowanie go asynchronicznie przy użyciu ASIO (asynchroniczne operacje we / wy). Dzięki temu możesz zbudować niesamowitą szybką usługę internetową (w połączeniu z nginx jako serwerem odwrotnego proxy i statycznym dla uzyskania najlepszych efektów); Połącz to z biblioteką szablonów, taką jak Wt, i możesz obsłużyć dziesiątki tysięcy żądań na sekundę z jednego serwera.

To, czy jest to praktyczna alternatywa dla frameworku dynamicznego języka, to inna kwestia.

vartec
źródło
9

Krótka odpowiedź brzmi: WSZYSTKO może zostać użyte do napisania strony internetowej, pod warunkiem, że może ona czytać dane wejściowe, zapisywać dane wyjściowe i jest wykonywalna przez serwer WWW.

Technicznie każdy język może być używany jako skrypt CGI, pod warunkiem, że:

  1. Interpretuje wszystkie dane wejściowe i środowisko przedstawione przez serwer
  2. Dane wyjściowe w znanym języku znaczników (zazwyczaj HTML)
  3. Może być uruchamiany przez serwer

Istnieją również inne sposoby. Perl ma możliwość budowania jako otoki wokół kodu c / c ++, działającego jako warstwa interpretacyjna między nimi (i nie obejmuje to modułów Perla, które są skompilowane płasko jako C).

Avatar_Squadron
źródło
7

na początku było dość powszechne - pierwszymi stronami, nad którymi pracowałem pod koniec lat 90. były rozszerzenia ISAPI napisane w C ++ i działały całkiem dobrze.

Steven A. Lowe
źródło
3
isapi.dll ktoś?
czerwono-brud
lub ATLServer - atlserver.codeplex.com
gbjbaanb
5

Wygląda na to, że Microsoft tak myśli. Sprawdź Casablankę, która jest nowym zestawem narzędzi dla (wydaje się) platformy Azure przy użyciu C ++.

Casablanca to projekt mający na celu zbadanie, jak najlepiej wspierać programistów C ++, którzy chcą skorzystać z radykalnej zmiany w architekturze oprogramowania, którą reprezentuje przetwarzanie w chmurze.

Oto, co otrzymujesz dzięki Casablance:

  • Obsługa dostępu do usług REST z natywnego kodu w Windows Vista, Windows 7 i Windows 8 Consumer Preview poprzez zapewnienie asynchronicznych powiązań C ++ z HTTP, JSON i URI
  • Zestaw SDK rozszerzenia Visual Studio do pisania kodu po stronie klienta C ++ HTTP w aplikacji w stylu Windows 8 Metro
  • Obsługa pisania REST z rodzimym kodem dla platformy Azure, w tym integracja z Visual Studio
  • Wygodne biblioteki do uzyskiwania dostępu do obiektów blob platformy Azure i magazynu kolejek od rodzimych klientów jako pierwszorzędna funkcja Platform-as-a-Service (PaaS)
  • Spójny i wydajny model do komponowania operacji asynchronicznych w oparciu o funkcje C ++ 11
  • Implementacja C ++ modelu programowania opartego na aktorach Erlanga
  • Zestaw próbek i dokumentacji
gbjbaanb
źródło
2

W przypadku PHP możesz pisać własne rozszerzenia C / C ++ i w ten sposób uzyskać dobre korzyści wydajnościowe. Gdybym miał część aplikacji WWW wymagającą dużej mocy obliczeniowej, prawdopodobnie stworzyłbym małą bibliotekę C ++, która odciążyłaby to przetwarzanie do rozszerzenia, a następnie zwróciłaby wynik z powrotem do PHP, a następnie PHP wyśle ​​go do przeglądarki.

Inną rzeczą, której ludzie często nie rozważają, jest odciążenie niektórych procesorów po stronie klienta, np. JavaScript / jQuery. Jeśli mam serwer sieciowy, mogę potrzebować procesora 3Ghz, aby wykonać intensywne przetwarzanie procesora dla określonej funkcji (być może przetwarzania danych). Moja firma co miesiąc płaci pieniądze za ten serwer, aby mógł nadal działać. Jeśli chcę skalować operacje dla 100 równoczesnych użytkowników wykonujących to zadanie intensywnie wykorzystujące procesor w tym samym czasie, być może potrzebuję wielu procesorów i serwerów, co zwiększy koszty mojej firmy. Jeśli odciążę to zadanie intensywnie wykorzystujące procesor po stronie klienta, każdy użytkownik odwiedzający witrynę może wykonać własne przetwarzanie danych i nie muszę zwiększać wydajności serwera, oszczędzając w ten sposób pieniądze.

W końcu z kolektywną mocą ponad 100 komputerów stacjonarnych / tabletów / telefonów komórkowych, które przetwarzają dla Ciebie, to o wiele więcej mocy niż twój serwer siedzący w centrum danych gdzieś kosztujący co miesiąc pieniądze biznesowe, aby móc dalej działać. Potencjalnie wtedy wszystko, co zrobiłby Twój serwer, polegałoby na pobieraniu danych z bazy danych, udostępnianiu treści oraz odrobinie wstępnego / końcowego przetwarzania i sprawdzania poprawności danych przed ich ponownym zapisaniem w bazie danych. Oczywiście nie spowodowałbyś zbyt dużego obciążenia procesora po stronie klienta, co mogłoby zablokować / zawiesić interfejs użytkownika przeglądarki internetowej, możesz odpalić żądanie AJAX na serwerze, pobrać dane, a następnie przetwarzać dane asynchronicznie po stronie klienta, opuszczając sieć -Ibrowser UI całkowicie użyteczny.

zuallauz
źródło
2

Tak, można go użyć. Inni wspominali o różnych podejściach. Oto moje własne podejście. Zaletą jest to, że jest całkowicie przenośny i niezależny, wszystkie wybrane biblioteki zależą tylko od ANSI C. Konfiguracja wymaga tylko jądra Linux i kompilatora C (i oczywistych rzeczy, takich jak Busybox, bash itp.) (Lub Windows i kompilator), nie są potrzebne żadne dodatkowe biblioteki, żadne wymyślne ogromne instalacje.

Rezultatem jest pojedynczy program, który jest zarówno serwerem sieciowym, jak i dynamicznym generatorem stron (zastępuje zarówno „apache”, jak i „php”), a także będzie miał dostęp do bazy danych przez sqlite.

Wykorzystane biblioteki:

  • Mongoose - serwer HTTP
  • Sqlite - baza danych SQL
  • MiniXML - Ułatwia dynamiczne generowanie strony. coś w rodzaju JavascriptcreateElement

Pozostała część tej odpowiedzi to kompletny przewodnik po konfiguracji dla systemu Linux. Zarówno SQlite, jak i MiniXML są opcjonalne, ale przewodnik obejmuje pełną instalację. Od Ciebie zależy, czy skomentujesz niepotrzebne części, jeśli chcesz wyłączyć sqlite lub MiniXML.

1. Pobierz 3 biblioteki

2. Przygotuj swój folder

  • Utwórz pusty folder (nazwiemy go folderem głównym)
  • Umieść w nim następujące pliki:
    • Z sqlite tar.gz: sqlite3.c , sqlite3.h
    • Z suwaka Mongoose: mongoose.c , mongoose.h
    • Z mxml tar.gz: mxml.h

3. Skompiluj mxml

Być może zauważyłeś brak pliku mxml.c, ponieważ musimy utworzyć statyczną bibliotekę mxml. Przejdź do folderu, w którym pobrany został plik mxml tar.gz, i wykonaj:

tar -xvf mxml-<version>.tar.gz #Extract the tar
cd mxml-<version> #Go to the newly extracted directory
./configure #prepare the compiler
make #compile, you may need to install "make" first.

Po zakończeniu kompilacji zostanie wygenerowanych wiele plików, jedynym interesującym nas libmxml.aplikiem jest skopiowanie go do folderu głównego.

3.1 Kontrola podwójna

Sprawdź, czy główny folder ma następujące elementy:

  • W przypadku mangusty: mongoose.c, mongoose.h
  • W przypadku mxml: libmxml.a, mxml.h
  • dla sqlite: sqlite.c, sqlite.h

4. main.c

Stwórzmy rzeczywisty program, utwórz main.cplik w głównym folderze, oto szkielet, aby zacząć.

#include <string.h>
#include <stdio.h>

#include "mongoose.h"
#include "mxml.h"
#include "sqlite3.h"

/***Sqlite initialization stuff***/
//comment out everything sqlite related if you don't want sqlite, including the callback function and the include "sqlite3.h"
static int callback(void * custom, int argc, char **argv, char **azColName);
char *zErrMsg = 0;
sqlite3 *db;
int rc;

/***Just some laziness shortcut functions I made***/
typedef mxml_node_t * dom; //type "dom" instead of "mxml_node_t *"
#define c mxmlNewElement   //type "c" instead of "mxmlNewElement"
inline void t(dom parent,const char *string) //etc
{
    mxmlNewText(parent, 0, string);
}

//type "sa" instead of "mxmlElementSetAttr"
inline void sa(dom element,const char * attribute,const char * value) 
{
    mxmlElementSetAttr(element,attribute,value);
}




//The only non boilerplate code around in this program is this function
void serve_hello_page(struct mg_connection *conn)
{
    char output[1000];
    mg_send_header(conn,"Content-Type","text/html; charset=utf-8");
    mg_printf_data(conn, "%s", "<!DOCTYPE html>");
    //This literally prints into the html document


    /*Let's generate some html, we could have avoided the
     * xml parser and just spat out pure html with mg_printf_data
     * e.g. mg_printF_data(conn,"%s", "<html>hello</html>") */

    //...But xml is cleaner, here we go:
            dom html=mxmlNewElement(MXML_NO_PARENT,"html");
                dom head=c(html,"head");
                    dom meta=c(head,"meta");
                    sa(meta,"charset","utf-8");
                dom body=c(html,"body");
                    t(body,"Hello, world<<"); //The < is auto escaped, neat!
                    c(body,"br");
                    t(body,"Fred ate bred");    
                dom table=c(body,"table");
                sa(table,"border","1");

                //populate the table via sqlite
                rc = sqlite3_exec(db, "SELECT * from myCoolTable", callback, table, &zErrMsg);
                if( rc!=SQLITE_OK )
                {
                    fprintf(stderr, "SQL error: %s\n", zErrMsg);
                    sqlite3_free(zErrMsg);
                }

            mxmlSaveString (html,output,1000,  MXML_NO_CALLBACK);
            mg_printf_data(conn, "%s", output);
            mxmlDelete(html); 
}

//sqlite callback
static int callback(void * custom, int argc, char **argv, char **azColName)
{
    //this function is executed for each row
    dom table=(dom)custom;

    dom tr=c(table,"tr");
    dom td;
    int i;
    for(i=0; i<argc; i++)
    {
        td=c(tr,"td");
        if (argv[i])
            t(td, argv[i]);
        else
            t(td, "NULL");

        printf("%s == %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
     printf("\n");
     return 0;
}


static int event_handler(struct mg_connection *conn, enum mg_event ev)
{
    if (ev == MG_AUTH)
    {
        return MG_TRUE;   // Authorize all requests
    }
    else if (ev == MG_REQUEST)
    {
        if (!strcmp(conn->uri, "/hello"))
        {
            serve_hello_page(conn);
            return MG_TRUE;   // Mark as processed
        }
    }
    return MG_FALSE;  // Rest of the events are not processed

}

int main(void)
{
    struct mg_server *server = mg_create_server(NULL, event_handler);
    //mg_set_option(server, "document_root", "."); //prevent dir listing and auto file serving
    //TODO can I allow file listing without dir listing in a specified directory?
    mg_set_option(server, "listening_port", "8080");


    rc = sqlite3_open("db.sqlite3", &db); 

    if( rc )
    {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return(1);
    }

    printf("Server is running on port 8080!\n");
    for (;;)
    {
        mg_poll_server(server, 1000);  // Infinite loop, Ctrl-C to stop
    }
    mg_destroy_server(&server);
    sqlite3_close(db);

    return 0;
}




/*
 * useful stuff:
 * mg_send_file(struct mg_connection *, const char *path); - serve the file at *path*/

Wreszcie kompilacja!

Kompilujmy się. cddo głównego folderu i wykonaj następujące czynności:

gcc -c main.c
gcc -c mongoose.c
gcc -c sqlite3.c
gcc -o server.out main.o mongoose.o sqlite3.o -ldl -lpthread -lmxml -L . 

Teraz uruchom server.out za pomocą /server.outi przejdź dolocalhost:8080/hello

Gotowy :)

Witaj świecie
źródło
@Hey: Dzięki za wskazanie tej alternatywy Mongoose, zawsze wolę projekty kierowane przez społeczność. Prawdopodobnie zastąpię Mongoose Civetweb w mojej odpowiedzi po dokładnym przetestowaniu.
Hello World,
0

Wydaje mi się, że kilka systemów wbudowanych (np. Routery, drukarki, ...) ma jakiś serwer WWW oparty na C ++.

W szczególności możesz użyć biblioteki serwera HTTP, takiej jak libonion, aby dodać pewne możliwości sieciowe do jakiegoś programu w C lub C ++ lub stworzyć lekki serwer z pewnym interfejsem internetowym.

Niektóre osoby kodują swój serwer WWW lub interfejs HTTP w Ocaml za pomocą Ocsigen . Nie każda strona internetowa to PHP. A dzięki FastCGI możesz dynamicznie przetwarzać strony w / do swojej aplikacji.

Basile Starynkevitch
źródło