web-dev-qa-db-fra.com

C ++ peut-il être utilisé comme langage de développement Web côté serveur?

Je voudrais me lancer dans le développement Web en utilisant C++ comme "langage de script" côté serveur. Mon infrastructure de serveur est basée sur * nix, donc le développement Web en C++ sur Azure n'est pas applicable et C++/CLI ASP.NET ne l'est pas non plus.

Indépendamment des applications CGI héritées, le développement Web peut-il se faire en C++?

34
Scott Davies

Absolument.

Il existe même plusieurs cadres pour les développer, notamment Wt , cppcms , CSP , et d'autres. L'implémentation principale de FastCGI est en C, et supporte directement plusieurs langues , y compris C++.

Tout langage de programmation capable d'analyser des chaînes peut être utilisé dans CGI ou dans un servlet. Tout langage pouvant implémenter des liaisons avec des bibliothèques C peut également être utilisé pour développer des modules pour des serveurs compatibles ISAPI ou Apache.

Ce n'est pas particulièrement facile en C++, et les bons moteurs de modélisation sont rares, mais cela peut être fait.

Bien sûr, la question de savoir si c'est une bonne idée est une tout autre affaire. :)

Remarque: Les principaux sites Web comme Amazon.com, eBay et Google utilisent C++ pour certaines parties de leur infrastructure. Sachez cependant que Google n'utilise que C++ pour les systèmes à vitesse critique, et qu'Amazon.com n'est que relativement récemment passé de LISP (ce qui a mis en colère certains de leurs cadres supérieurs :).

Facebook a précédemment compilé PHP en C++, mais leur compilateur HipHop (écrit en partie en C++) a depuis été réoutillé comme une machine virtuelle bytecode.

56
greyfade

Pourquoi pas?

Le site de rencontres OkCupid est créé avec C++. Il y a probablement d'autres exemples.

Il existe également une boîte à outils inspirée de Qt pour développer des applications Web avec C++ appelée Wt .

18
Vitor Py

Si vous prévoyez d'écrire votre application Web en C++, ce serait un gaspillage total de l'interfacer en tant que CGI.

Ma suggestion serait de le construire asynchrone en utilisant ASIO (E/S asynchrones). Avec cela, vous pouvez créer un service Web extrêmement rapide (combiner avec nginx en tant que proxy inverse et un serveur statique pour les meilleurs effets); Combinez cela avec une bibliothèque de modèles comme Wt et vous êtes prêt à servir des dizaines de milliers de requêtes par seconde à partir d'un seul serveur.

Que ce soit une alternative pratique au cadre Web de langage dynamique est un autre problème.

11
vartec

La réponse courte est: TOUT peut être utilisé pour écrire une page Web à condition qu'il puisse lire l'entrée, écrire une sortie interprétable et être exécutable par le serveur Web.

Techniquement, n'importe quelle langue peut être utilisée comme script CGI à condition:

  1. Interprète toutes les entrées et l'environnement tels que présentés par le serveur
  2. Sorties dans un langage de balisage connu (généralement html)
  3. Peut être exécuté par le serveur

Il existe également d'autres moyens. Perl a la capacité d'être construit comme un wrapper autour du code c/c ++, agissant comme une couche d'interprétation entre les deux (et cela n'inclut pas les modules Perl qui sont à plat compilés en C).

9
Avatar_Squadron

au début, c'était assez courant - les premiers sites Web sur lesquels j'ai travaillé à la fin des années 1990 étaient des extensions ISAPI écrites en C++, et elles fonctionnaient assez bien.

7
Steven A. Lowe

Il semble que Microsoft le pense aussi. Découvrez Casablanca qui est un nouvel ensemble d'outils pour (il apparaît) Azure utilisant C++.

Casablanca est un projet visant à explorer la meilleure façon de soutenir les développeurs C++ qui souhaitent profiter du changement radical de l'architecture logicielle que représente le cloud computing.

Voici ce que vous obtenez avec Casablanca:

  • Prise en charge de l'accès aux services REST à partir du code natif sur Windows Vista, Windows 7 et Windows 8 Consumer Preview en fournissant des liaisons C++ asynchrones à HTTP, JSON et URI
  • Un SDK d'extension Visual Studio pour vous aider à écrire du code côté client HTTP C++ dans votre application de style Metro Windows 8
  • Prise en charge de l'écriture de code natif REST pour Azure, y compris l'intégration de Visual Studio
  • Bibliothèques pratiques pour accéder au stockage d'objets blob et de files d'attente Azure à partir de clients natifs en tant que fonctionnalité de première classe Platform-as-a-Service (PaaS)
  • Un modèle cohérent et puissant pour composer des opérations asynchrones basées sur les fonctionnalités C++ 11
  • Une implémentation C++ du modèle de programmation basé sur les acteurs d'Erlang
  • Un ensemble d'exemples et de documentation
5
gbjbaanb

Pour PHP vous pouvez écrire vos propres extensions C/C++ et obtenir de bons avantages en termes de performances de cette façon. Si j'avais une partie très gourmande en CPU de mon application web, je le ferais probablement créer une petite bibliothèque C++ qui a déchargé ce traitement vers l'extension puis renvoyé le résultat au PHP puis le PHP le renvoie au navigateur).

L'autre chose que les gens ne considèrent pas souvent est de décharger certains traitements CPU du côté client, par ex. JavaScript/jQuery. Si j'ai un serveur Web, je pourrais avoir besoin d'un CPU 3Ghz pour faire un traitement intensif CPU pour une fonction particulière (peut-être du traitement de données). Mon entreprise paie de l'argent pour ce serveur chaque mois pour le faire fonctionner. Si je souhaite faire évoluer les opérations pour 100 utilisateurs simultanés exécutant simultanément cette tâche gourmande en processeur, j'ai peut-être besoin de plusieurs processeurs et serveurs, ce qui augmente les coûts pour mon entreprise. Si je décharge cette tâche gourmande en CPU du côté client, chaque utilisateur qui visite le site Web peut effectuer son propre traitement sur les données et je n'ai pas à augmenter la capacité de mon serveur, ce qui me fait économiser de l'argent.

Après tout, avec la puissance collective de plus de 100 ordinateurs de bureau/tablettes/mobiles faisant le traitement pour vous, c'est beaucoup plus de puissance que votre serveur assis dans un centre de données quelque part, ce qui coûte de l'argent à votre entreprise chaque mois pour continuer à fonctionner. Potentiellement, tout ce que votre serveur ferait serait de récupérer les données de la base de données, de servir le contenu et un peu de pré/post-traitement et de validation des données avant de les stocker de nouveau dans la base de données. Évidemment, vous ne rendriez pas le code côté client trop gourmand en CPU, ce qui pourrait bloquer/geler l'interface utilisateur du navigateur Web, vous pourriez envoyer une requête AJAX au serveur, récupérer les données puis traiter la les données côté client de manière asynchrone, laissant l'interface utilisateur du navigateur Web complètement utilisable.

2
zuallauz

Oui, il peut être utilisé. Les autres ont mentionné différentes approches. Voici ma propre approche. L'avantage est qu'il est totalement portable et autonome, toutes les bibliothèques choisies ne dépendent que d'ANSI C. La configuration ne nécessite que le noyau Linux et un compilateur C (Et les choses évidentes comme Busybox, bash, etc.) (ou Windows et un compilateur), aucune bibliothèque supplémentaire n'est nécessaire, aucune installation gigantesque.

Le résultat est un programme unique qui est à la fois un serveur Web et un générateur de page dynamique (remplace à la fois "Apache" et "php"), il aura également accès à la base de données via sqlite.

Bibliothèques utilisées:

  • Mongoose - serveur Http
  • Sqlite - Base de données SQL
  • MiniXML - facilite la génération de pages dynamiques. un peu comme Javascript createElement

Le reste de cette réponse est un guide d'installation complet pour Linux. SQlite et MiniXML sont facultatifs, mais le guide couvre l'installation complète. C'est à vous de commenter les parties non nécessaires si vous souhaitez désactiver sqlite ou MiniXML.

1. Téléchargez les 3 bibliothèques

2. Préparez votre dossier

  • Créez un dossier vide (nous l'appellerons le dossier principal)
  • Mettez-y les fichiers suivants:
    • Depuis sqlite tar.gz: sqlite3.c , sqlite3.h
    • Depuis le Zip Mongoose: mongoose.c , mongoose.h
    • Depuis le mxml tar.gz: mxml.h

3. Compiler mxml

Vous avez peut-être remarqué que mxml.c est manquant, c'est parce que nous devons créer une bibliothèque mxml statique. Accédez au dossier dans lequel le fichier mxml tar.gz a été téléchargé et effectuez:

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.

Une fois la compilation terminée, de nombreux fichiers seront générés, le seul fichier qui nous intéresse est libmxml.a, copiez ce fichier dans le dossier principal.

3.1 Double vérification

Vérifiez que le dossier principal contient les éléments suivants:

  • Pour la mangouste: mongoose.c, mongoose.h
  • Pour mxml: libmxml.a, mxml.h
  • pour sqlite: sqlite.c, sqlite.h

4. main.c

Créons le programme réel, créons un main.c fichier dans le dossier principal, voici un squelette pour commencer.

#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*/

Enfin, compilation!

Compilons. cd dans votre dossier principal et exécutez-les:

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 . 

Maintenant, exécutez server.out avec /server.out et accédez à localhost:8080/hello

Terminé :)

2
Hello World

Je suppose que plusieurs systèmes embarqués (par exemple, les routeurs, les imprimantes, ...) ont un serveur Web piloté par C++.

En particulier, vous pouvez utiliser une bibliothèque de serveur HTTP comme libonion pour ajouter des fonctionnalités Web à un programme C ou C++, ou pour développer un serveur léger avec une interface Web.

Certaines personnes codent leur serveur Web ou leur interface HTTP dans Ocaml en utilisant Ocsigen . Tous les éléments du Web ne sont pas PHP. Et avec FastCGI , vous pouvez effectuer un traitement Web dynamique dans/vers votre application.

0