Evet, kullanılabilir. Diğerleri çeşitli yaklaşımlardan bahsetti. İşte benim kendi yaklaşımım. Avantajı tamamen taşınabilir ve kendi kendine yeten olmasıdır, seçilen tüm kütüphaneler yalnızca ANSI C'ye bağlıdır. Ayarlama yalnızca Linux Çekirdeği ve bir C derleyicisi gerektirir (ve Busybox, bash, vb. Gibi belirgin şeyler) (veya Windows ve bir derleyici), fazladan kütüphaneye gerek yok, çok fazla büyük kurulum gerektirmiyor.
Sonuç, hem web sunucusu hem de dinamik sayfa üreteci olan tek bir programdır (hem "apache" hem de "php" yi değiştirir), ayrıca sqlite üzerinden veri tabanı erişimine sahip olacaktır.
Kullanılan kütüphaneler:
- Mongoose - Http sunucusu
- Sqlite - SQL Veritabanı
- MiniXML - Dinamik sayfa oluşturmayı kolaylaştırır. Javascript benzeri bir şey
createElement
Bu cevabın geri kalanı Linux için eksiksiz bir kurulum rehberidir. Hem SQlite hem de MiniXML isteğe bağlıdır, ancak kılavuz tam kurulumu kapsar. Sqlite veya MiniXML'yi devre dışı bırakmakla ilgilenmiyorsanız, gerekli olmayan parçaları yorumlamak size kalmıştır.
1. 3 kütüphaneyi indirin
2. Klasörünüzü hazırlayın
- Boş bir klasör oluşturun (Ana klasör diyoruz)
- Aşağıdaki dosyaları içine yerleştirin:
- Sqlite tar.gz'den:
sqlite3.c , sqlite3.h
- Mongoose zip’inden:
mongoose.c , mongoose.h
- Mxml tar.gz'den:
mxml.h
3. mxml'yi derleyin
Mxml.c'nin eksik olduğunu fark etmiş olabilirsiniz, bunun nedeni statik bir mxml kütüphanesi oluşturmamız gerektiğidir. Mxml tar.gz dosyasının indirildiği klasöre gidin ve gerçekleştirin:
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.
Derleme tamamlandığında, birçok dosya oluşturulacak, ilgilendiğimiz tek dosya libmxml.a
bu dosyayı ana klasöre kopyalamaktır.
3.1 Şüphe
Ana klasörde aşağıdakilerin olup olmadığını kontrol edin:
- Gelincik için:
mongoose.c, mongoose.h
- Mxml için:
libmxml.a, mxml.h
- sqlite için:
sqlite.c, sqlite.h
4. ana.c
Haydi asıl programı oluşturalım main.c
, ana klasörde bir dosya oluşturalım , işte başlayabilmen için bir iskelet.
#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*/
Sonunda derleme!
Derleyelim. cd
Ana klasörünüze ekleyin ve bunları yürütün:
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 .
Şimdi server.out ile yürütün /server.out
ve şuraya gidin:localhost:8080/hello
Tamam :)