Oui, il peut être utilisé. Les autres ont mentionné diverses approches. Voici ma propre approche. L’avantage est qu’elle est totalement portable et autonome. Toutes les bibliothèques sélectionnées dépendent uniquement de ANSI C. Pour le configurer, il suffit de disposer du noyau Linux et d’un compilateur C et un compilateur), pas de bibliothèques supplémentaires sont nécessaires, pas de grandes installations de fantaisie.
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 disposera également d'un 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 complet de configuration pour Linux. SQlite et MiniXML sont facultatifs, mais le guide couvre l’installation complète. Il vous appartient de commenter les parties inutiles 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 les fichiers suivants dedans:
- De la sq.gite tar.gz:
sqlite3.c , sqlite3.h
- Du zip Mongoose:
mongoose.c , mongoose.h
- Du mxml tar.gz:
mxml.h
3. Compiler le mxml
Vous avez peut-être remarqué que mxml.c est manquant, car nous devons créer une bibliothèque statique mxml. Accédez au dossier de téléchargement du fichier .txz tar.gz et effectuez les opérations suivantes:
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 de libmxml.a
copier ce fichier dans le dossier principal.
3.1 Doublecheck
Vérifiez que le dossier principal présente les éléments suivants:
- Pour la mangouste:
mongoose.c, mongoose.h
- Pour le mxml:
libmxml.a, mxml.h
- pour sqlite:
sqlite.c, sqlite.h
4. main.c
Créons le programme actuel, créons un main.c
fichier dans le dossier principal, voici un squelette pour vous aider à démarrer.
#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, compiler!
Compilons. cd
dans votre dossier principal et exécutez ceux-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 .
Maintenant, exécutez server.out avec /server.out
et naviguez jusqu’àlocalhost:8080/hello
Terminé :)