Sí, se puede usar. Los otros han mencionado varios enfoques. Aquí está mi propio enfoque. La ventaja es que es totalmente portátil y autónomo, todas las bibliotecas seleccionadas solo dependen de ANSI C. La configuración solo requiere el kernel de Linux y un compilador de C (y las cosas obvias como Busybox, bash, etc.) (o Windows y un compilador), no se necesitan bibliotecas adicionales, ni grandes instalaciones sofisticadas.
El resultado es un único programa que es a la vez un servidor web y un generador de páginas dinámicas (Sustituye "apache" y "php"), también tendrá acceso a la base de datos a través de sqlite.
Bibliotecas utilizadas:
- Mangosta - servidor HTTP
- SQLite - Base de datos SQL
- MiniXML: facilita la generación dinámica de páginas. algo así como Javascript's
createElement
El resto de esta respuesta es una guía de configuración completa para Linux. Tanto SQlite como MiniXML son opcionales, pero la guía cubre la instalación completa. Depende de usted comentar las partes no necesarias si está interesado en deshabilitar sqlite o MiniXML.
1. Descargue las 3 bibliotecas
2. Prepare su carpeta
- Cree una carpeta vacía (la llamaremos la carpeta principal)
- Pon los siguientes archivos en él:
- Desde el sqlite tar.gz:
sqlite3.c , sqlite3.h
- Desde el zip de Mangosta:
mongoose.c , mongoose.h
- Desde el mxml tar.gz:
mxml.h
3. Compilar mxml
Es posible que haya notado que falta mxml.c, esto se debe a que necesitamos crear una biblioteca estática de mxml. Vaya a la carpeta donde se descargó el mxml tar.gz y realice:
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.
Una vez finalizada la compilación, se generarán muchos archivos, el único archivo que nos interesa es libmxml.a
copiar ese archivo en la carpeta principal.
3.1 Doublecheck
Verifique que la carpeta principal tenga lo siguiente:
- Para la mangosta:
mongoose.c, mongoose.h
- Para mxml:
libmxml.a, mxml.h
- para sqlite:
sqlite.c, sqlite.h
4. main.c
Creemos el programa real, cree un main.c
archivo en la carpeta principal, aquí hay un esqueleto para que pueda comenzar.
#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*/
Finalmente, compilando!
Vamos a compilar cd
a su carpeta principal y ejecute estos:
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 .
Ahora, ejecute server.out con /server.out
y navegue hastalocalhost:8080/hello
Hecho :)