可以将C ++用作服务器端Web开发语言吗?[关闭]


34

我想在服务器端使用C ++作为“脚本语言”进行Web开发。我的服务器基础结构是基于* nix的,因此不适用在Azure上使用C ++进行Web开发,并且也不适用C ++ / CLI ASP.NET。

与传统的CGI应用程序分开,是否可以使用C ++进行Web开发?


33
当然有可能,问题是;是实用
Ed S.

在stackoverflow.com上看到此问题
凯文·克莱恩

24
如果您愿意的话,可以将汇编语言用作服务器端语言。
Channel72 2011年

8
甚至Brainf *如果CK ,.被重定向到一个插座。
dan04'3

4
这带回了我参与的第一个Web项目的恐怖回忆。CGI网关到C代码。当我想到它时,我仍然发抖!:-)
Brian Knoblauch

Answers:


56

绝对。

甚至有几个开发框架,包括WtcppcmsCSP以及其他。FastCGI的主线实现使用C语言,并直接支持多种语言,包括C ++。

可以解析字符串的任何编程语言都可以在CGI或Servlet中使用。可以与C库实现绑定的任何语言也可以用于开发与ISAPI或Apache兼容的服务器的模块。

在C ++中,这并不是特别容易,并且好的模板引擎很少而且相差很远,但是可以做到。

当然,这是否是一个好主意完全是另一回事。:)

请注意: Amazon.com,eBay和Google等主要网站的部分基础架构都使用C ++。但是请意识到,Google仅将C ++用于对速度要求严格的系统,而Amazon.com只是最近才退出使用Lisp(这激怒了他们的一些高级职员:)。

Facebook以前将PHP编译为C ++,但后来将其HipHop编译器(部分用C ++编写)已重新构建为字节码虚拟机。


2
+1用于引用各种框架。你应该补充一点,是很常见的(极)大的网络应用程序用C供电++(和其他语言):amazon.com,google.com,现在facebook.com通过街舞等
KLAIM

7
@Klaim:这很常见,但这绝不是规则。亚马逊的架构历来是基于Lisp的,直到最近才用C ++重写。Google的架构涉及Java,Python和其他语言的频率几乎与C ++相同,都是出于各种原因。Facebook现在仅使用hiphop,因为他们发现PHP无法扩展。:)
greyfade

4
我同意,但是我的意思是它们仍然是使用C ++的著名示例-直接回答原始问题标题。
2011年

1
@johannes Facebook的扩展性问题源于这样一个事实,即它们必须维护比其他必要数量更多的服务器,特别是由于优化的PHP脚本的性能较差。对于如此庞大的基础架构,线性缩放根本不够好。但是请记住,“无共享”方法并不是PHP独有的。C和C ++也可以做到这一点。
greyfade 2013年

1
@amar事情是没有回报的,除了需要原始性能的应用程序的0.1%。有了良好的Web堆栈支持,您可以用其他大多数语言在1/3的时间内提供服务。银行,网络广告商等都可以大规模使用而不使用C ++。甚至Facebook。推特。堆栈溢出。都是用高级语言完成的。它会留在这里,但不会再次成为多数。大概曾经。
钻机

18

为什么不?

OkCupid交友网站与C ++创建的。可能还有其他示例。

还有一个受Qt启发的工具包,用于使用C ++开发Web应用程序,称为Wt


11
“为什么不呢?” 因为使用对这种事情有更多支持的语言要容易得多。
Ed S.

5
@EdS。正如我和greyfade指出的那样,存在使用C ++开发Web应用程序的框架。
Vitor Py

2
是的,但是再次重申,它们是否像更常用的框架一样易于使用?老实说,我不是Web开发人员,我从未使用过它们,但是有一些事情告诉我,它们可能不如(例如)ruby / python / PHP同类产品那样成熟或广泛使用。
Ed S.

3
@EdS .: Ruby和Python都不都是从Web框架开始的。实际上,花了十年的时间才出现。框架是足够多的人想要使用语言X来解决问题Y的唯一结果。对于C ++,同样可能发生。不能这样做的主要原因:C ++无法管理,需要花很多时间才能编译,并且通常具有更高的入口壁垒。
back2dos

1
@ back2dos:谁说这两种语言都是在考虑网络开发的?我当然没有。我使用了“支持”一词。
Ed S.

11

如果您打算用C ++编写Web应用程序,那么将其作为CGI接口将是完全浪费的。

我的建议是使用ASIO(异步I / O)异步构建它。这样,您就可以构建出色的快速Web服务(与nginx结合使用,作为反向代理和静态服务器,以达到最佳效果);将其与Wt之类的模板库结合起来,您就可以从一台服务器每秒处理数万个请求。

这是否可以替代动态语言Web框架是另一个问题。


9

简短的答案是,只要可以读取输入,编写可解释的输出并且可由Web服务器执行,则任何东西都可以用来编写网页。

从技术上讲,可以将任何语言用作CGI脚本:

  1. 解释服务器提供的所有输入和环境
  2. 以已知的标记语言(通常为html)输出
  3. 可以由服务器运行

也有其他方法。Perl能够被构建为c / c ++代码的包装器,充当两者之间的解释层(并且这不包括平坦地编译为C的perl模块)。


7

最初,它很普遍-我在1990年代后期研究的第一个网站是用C ++编写的ISAPI扩展,并且运行良好。


3
isapi.dll有人吗?
红尘

或ATLServer-atlserver.codeplex.com –
gbjbaanb

5

微软似乎也认为可以。签出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 ++实现
  • 一组样本和文档

2

对于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完全可用。


2

是的,可以使用。其他人提到了各种方法。这是我自己的方法。优点是它是完全可移植且自包含的,所有选择的库仅依赖于ANSIC。对其进行设置仅需要Linux内核和C编译器(以及诸如Busybox,bash等显而易见的东西)(或Windows)和编译器),不需要额外的库,也不需要花哨的庞大安装。

结果是一个既是Web服务器又是动态页面生成器的单一程序(替换为“ 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仔细检查

检查主文件夹是否具有以下内容:

  • 对于猫鼬: 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

完成:)



@Hey:感谢您指出此Mongoose替代方案,我始终更喜欢社区驱动的项目。在对它进行彻底测试之后,我可能会用Civetweb代替Mongoose。
Hello World

0

我猜几个嵌入式系统(例如路由器,打印机等)都有一些C ++驱动的Web服务器。

特别是,您可以使用诸如libonion之类的HTTP服务器库向某些C或C ++程序中添加某些Web功能,或者开发具有某些Web界面的轻型服务器。

有些人正在使用Ocsigen在Ocaml中编码其Web服务器或HTTP接口。并非每个网络事物都是PHP。使用FastCGI,您可以在应用程序中进行一些动态Web处理。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.