it-swarm.cn

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

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

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

34
Scott Davies

绝对。

甚至有几种开发它们的框架,包括 Wtcppcms[〜#〜] 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++编写))重新构建为字节码虚拟机。

56
greyfade

为什么不?

OkCupid 约会网站是使用C++创建的。可能还有其他示例。

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

18
Vitor Py

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

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

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

11
vartec

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

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

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

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

9
Avatar_Squadron

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

7
Steven A. Lowe

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

对于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
zuallauz

是的,可以使用。其他人提到了各种方法。这是我自己的方法。优点是它是完全可移植且自包含的,所有选择的库仅依赖于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

完成:)

2
Hello World

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

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

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

0
Basile Starynkevitch