我想在服务器端使用C ++作为“脚本语言”进行Web开发。我的服务器基础结构是基于* nix的,因此不适用在Azure上使用C ++进行Web开发,并且也不适用C ++ / CLI ASP.NET。
与传统的CGI应用程序分开,是否可以使用C ++进行Web开发?
,
都.
被重定向到一个插座。
我想在服务器端使用C ++作为“脚本语言”进行Web开发。我的服务器基础结构是基于* nix的,因此不适用在Azure上使用C ++进行Web开发,并且也不适用C ++ / CLI ASP.NET。
与传统的CGI应用程序分开,是否可以使用C ++进行Web开发?
,
都.
被重定向到一个插座。
Answers:
绝对。
甚至有几个开发框架,包括Wt,cppcms,CSP以及其他。FastCGI的主线实现使用C语言,并直接支持多种语言,包括C ++。
可以解析字符串的任何编程语言都可以在CGI或Servlet中使用。可以与C库实现绑定的任何语言也可以用于开发与ISAPI或Apache兼容的服务器的模块。
在C ++中,这并不是特别容易,并且好的模板引擎很少而且相差很远,但是可以做到。
当然,这是否是一个好主意完全是另一回事。:)
请注意: Amazon.com,eBay和Google等主要网站的部分基础架构都使用C ++。但是请意识到,Google仅将C ++用于对速度要求严格的系统,而Amazon.com只是最近才退出使用Lisp(这激怒了他们的一些高级职员:)。
Facebook以前将PHP编译为C ++,但后来将其HipHop编译器(部分用C ++编写)已重新构建为字节码虚拟机。
微软似乎也认为可以。签出Casablanca,这是使用C ++的(看来)Azure的新工具集。
卡萨布兰卡(Casablanca)是一个项目,旨在探索如何最好地支持希望利用云计算所代表的软件架构的根本转变的C ++开发人员。
这是您在卡萨布兰卡获得的东西:
- 通过提供对HTTP,JSON和URI的异步C ++绑定,支持从Windows Vista,Windows 7和Windows 8 Consumer Preview上的本地代码访问REST服务。
- 一个Visual Studio扩展SDK,可帮助您在Windows 8 Metro风格的应用程序中编写C ++ HTTP客户端代码
- 支持编写用于Azure的本机代码REST,包括Visual Studio集成
- 方便的库,用于从本地客户端访问Azure blob和队列存储,作为一流的平台即服务(PaaS)功能
- 基于C ++ 11功能组成异步操作的一致而强大的模型
- 基于Erlang actor的编程模型的C ++实现
- 一组样本和文档
对于PHP,您可以编写自己的C / C ++扩展,并以此方式获得良好的性能优势。如果我的Web应用程序中确实有CPU密集型部分,我可能会制作一个小型C ++库,该库将处理工作分流到扩展程序,然后将结果返回给PHP,然后PHP将其输出到浏览器。
人们不常考虑的另一件事是将某些CPU处理工作卸载到客户端,例如JavaScript / jQuery。如果我有一个Web服务器,则可能需要一个3Ghz CPU来为特定功能进行CPU密集型处理(可能是一些数据处理)。我的公司每月为该服务器付费,以保持其运行。如果要为100个同时运行该CPU密集型任务的并发用户扩展操作,则可能需要多个CPU和服务器,这会增加业务成本。如果我将CPU密集型任务分担给客户端,那么访问该网站的每个用户都可以对数据进行自己的处理,而不必增加服务器功能,从而节省了资金。
毕竟,归功于100多种台式机/平板电脑/移动设备的集体力量,为您处理数据的能力比位于数据中心中的服务器要强大得多,而每月花费您的业务资金来维持运转。然后,您的服务器可能要做的就是从数据库中检索数据,提供内容以及在存储回数据库中之前对数据进行一些前/后处理和验证。显然,您不会使客户端代码占用过多的CPU资源,这可能会阻塞/冻结Web浏览器UI,您可能会向服务器触发AJAX请求,检索数据,然后异步处理客户端数据,从而离开Web浏览器UI完全可用。
是的,可以使用。其他人提到了各种方法。这是我自己的方法。优点是它是完全可移植且自包含的,所有选择的库仅依赖于ANSIC。对其进行设置仅需要Linux内核和C编译器(以及诸如Busybox,bash等显而易见的东西)(或Windows)和编译器),不需要额外的库,也不需要花哨的庞大安装。
结果是一个既是Web服务器又是动态页面生成器的单一程序(替换为“ apache”和“ php”),它还将通过sqlite访问数据库。
使用的库:
createElement
该答案的其余部分是Linux的完整设置指南。SQlite和MiniXML都是可选的,但指南涵盖了完整的安装。如果您有兴趣禁用sqlite或MiniXML,请自行注释掉不需要的部分。
1.下载3个库
2.准备文件夹
sqlite3.c , sqlite3.h
mongoose.c , mongoose.h
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仔细检查
检查主文件夹是否具有以下内容:
mongoose.c, mongoose.h
libmxml.a, mxml.h
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
完成:)