ใช่มันสามารถใช้งานได้ คนอื่น ๆ ได้กล่าวถึงวิธีการต่างๆ นี่คือแนวทางของฉันเอง ข้อดีคือมันเป็นแบบพกพาและอยู่ในตัวเองห้องสมุดที่เลือกทั้งหมดขึ้นอยู่กับ ANSI C เท่านั้นการตั้งค่าต้องใช้เคอร์เนล Linux และคอมไพเลอร์ C (และสิ่งที่ชัดเจนเช่น Busybox, ทุบตี ฯลฯ ) (หรือ Windows และคอมไพเลอร์) ไม่จำเป็นต้องใช้ไลบรารีเพิ่มเติมไม่มีการติดตั้งขนาดใหญ่แฟนซี
ผลที่ได้คือโปรแกรมเดียวซึ่งเป็นทั้งเว็บเซิร์ฟเวอร์และตัวสร้างหน้าแบบไดนามิก (ทดแทนทั้ง "apache" และ "php") มันจะมีการเข้าถึงฐานข้อมูลผ่าน sqlite
ห้องสมุดที่ใช้:
- พังพอน - เซิร์ฟเวอร์ HTTP
- Sqlite - ฐานข้อมูล SQL
- MiniXML - ทำให้การสร้างเพจแบบไดนามิกง่ายขึ้น ประเภทของ Javascript
createElement
ส่วนที่เหลือของคำตอบนี้เป็นคู่มือการตั้งค่าที่สมบูรณ์สำหรับ Linux ทั้ง SQlite และ MiniXML เป็นทางเลือก แต่คู่มือครอบคลุมการติดตั้งแบบเต็ม มันขึ้นอยู่กับคุณที่จะแสดงความคิดเห็นชิ้นส่วนที่ไม่จำเป็นหากคุณสนใจที่จะปิดการใช้งาน sqlite หรือ MiniXML
1. ดาวน์โหลด 3 ไลบรารี
2. เตรียมโฟลเดอร์ของคุณ
- สร้างโฟลเดอร์ว่าง (เราจะเรียกมันว่าโฟลเดอร์หลัก)
- วางไฟล์ต่อไปนี้ลงไป:
- จาก sqlite tar.gz:
sqlite3.c , sqlite3.h
- จากพังพอนซิป:
mongoose.c , mongoose.h
- จาก mxml tar.gz:
mxml.h
3. รวบรวม mxml
คุณอาจสังเกตว่า mxml.c หายไปนี่เป็นเพราะเราจำเป็นต้องสร้างไลบรารี mxml แบบคงที่ ไปที่โฟลเดอร์ที่ดาวน์โหลด mxml tar.gz และทำงาน:
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.
เมื่อการรวบรวมเสร็จสิ้นไฟล์จำนวนมากจะถูกสร้างขึ้นไฟล์เดียวที่เราสนใจคือlibmxml.a
คัดลอกไฟล์นั้นไปไว้ในโฟลเดอร์หลัก
3.1 Doublecheck
ตรวจสอบว่าโฟลเดอร์หลักมีดังต่อไปนี้:
- สำหรับพังพอน:
mongoose.c, mongoose.h
- สำหรับ mxml:
libmxml.a, mxml.h
- สำหรับ sqlite:
sqlite.c, sqlite.h
4. main.c
มาสร้างโปรแกรมจริงสร้างmain.c
ไฟล์ในโฟลเดอร์หลักต่อไปนี้เป็นโครงกระดูกสำหรับคุณในการเริ่มต้น
#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*/
ในที่สุดก็รวบรวม!
รวบรวมกัน cd
ไปที่โฟลเดอร์หลักของคุณและดำเนินการเหล่านี้:
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 .
ตอนนี้รัน server.out ด้วย/server.out
และไปที่localhost:8080/hello
เสร็จแล้ว :)