使用C++建立网站,这有可能吗?
是的!
我知道这听起来很奇怪,甚至可能是徒劳无益的练习,但事实并非如此。
在本文中,我将解释如何使用C++开发网站以及考虑这样做的一些具体原因。
这不但很有趣,而且也可能是非常实用的。
主机环境
您可能会认为,只有在专用环境中才可以进行如此有趣的配置,但通常情况并非如此。尽管专用服务器或虚拟专用服务器对于大多数站点(不仅仅是C++站点)来说都是理想的选择,但在大多数情况下,您可以将C++与共享主机一起使用。
任何支持CGI的Web主机(几乎是所有)都支持使用C++构建的网站。根据主机提供商的不同,您可能无法在本地编译站点,或者可能必须为您的帐户启用编译器。请确认是否打算在Web服务器本身上通过SSH编辑和编译。
一个简单的例子
在要使用的示例中,我将假定一个共享的cPanel网络托管帐户。您可以通过对Apache配置进行一些简单的修改就很容易地将这些技术应用于虚拟或专用服务器或Amazon EC2实例。
cPanel为我们提供了一个cgi-bin文件夹,但这不是必需的。因为在大多数情况下,任何具有.cgi扩展名的文件,如果具有正确的权限(通常为0755),都将被自动处理。以下是必要的文件(请确保在Makefile中使用TAB)。
Makefile:
all:
g++ -O3 -s hello.cpp -o hello.cgi
clean:
rm -f hello.cgi
hello.cpp:
#include <iostream>
#include <string>
#include <stdlib.h>using namespace std;
void set_content_type(string content_type) {
cout << “Content-type: “ << content_type << “\r\n\r\n”;
}
void set_page_title(string title) {
cout << “<title>” << title << “</title>\n”;
}
void h1_text(string text) {
cout << text << “\n”;
}
int main() {
set_content_type(“text/html”); // Output HTML boilerplate
cout << “<!doctype html>\n”;
cout << “<html lang=\”en\”>\n”;
cout << “<head>\n”;
set_page_title(“Hello, World!”);
cout << “</head>\n”;
cout << “<body>\n”;
h1_text(“Hello, World!”);
cout << “</body>\n”;
cout << “</html>”; return 0;
}
如果您的帐户启用了编译器(您可能需要询问您的网络托管支持团队),只需SSH到您的帐户,然后将这些文件放入public_html文件夹中,接着运行:
make
将生成一个hello.cgi文件。如果您在浏览器中浏览该文件,如下所示:
http://your-test-site.com/hello.cgi
用您的域名或托管URL替换your-test-site.com。您应该能在屏幕上看到“Hello World”。
在深入研究代码本身之前,让我们回顾一下通过网络服务器进行工作的过程。当Apache收到请求时,它首先查找内部处理程序或重写规则,然后在磁盘上检查与该请求匹配的文件。在我们的例子中,它找到hello.cgi并执行它。我们的程序不输入任何内容,仅输出一个hello world消息。然后,Apache获取该内容并将其返回给用户。
至于代码本身,值得一提的是它可能更简单。我不必包含单独的函数set_content_type,set_page_title和h1_text,这些仅仅是使主要功能保持清洁的辅助函数。您可以简单地在main函数中输出所有这些内容。
但我希望您看到定义这些函数的好处。如果要为每个常见的HTML元素创建一个函数,则可以使用如下代码直接在C++程序中创建非常干净的响应:
void p(string text) {
cout << “<p>” << text << “</p>\n”;
}
然后,您可以使用类似:
p(“This would be paragraph text.”);
输出一个段落。
您甚至可以扩展这个想法,以使用p,h1_text等辅助函数,返回文本,而不是通过cout直接输出到标准输出。这样,您可以构建一个模板系统或嵌套响应,以使用非常精简且高效的C++代码创建非常复杂的页面。
查看所有输入
我们的示例没有任何有意义的输入。它仅返回“ Hello,World”。但是,对于每个请求,Apache都会通过环境变量向程序发送大量信息。您可以使用C标准库中的 getenv()函数获取这些值(不要忘记在文件顶部添加“ #include”)。
例如,如果您想知道完整的请求URI,则可以使用:
string request_uri = getenv(“REQUEST_URI”);
其他有用的变量是:
·REMOTE_ADDR-获取访客的IP地址
·REQUEST_METHOD-返回请求用到的方法(即GET,POST等)
·DOCUMENT_ROOT-网站的根目录(在共享系统上通常为〜/public_html,在虚拟/专用服务器上通常为/var /www /html)。
·QUERY_STRING-GET请求的查询字符串。您可以使用它来检索GET变量。
一个更强大的例子
当然可以手动解析GET变量,并且可以通过检查标准输入来完成POST变量的处理。您甚至可以通过更改请求和响应标头来获取和设置Cookie。
您可以编写自己的包装程序,也可以使用GNU cgicc库。它包含用于修改HTML和处理表单的辅助函数。对于大型项目,使用这样的库将节省大量时间。
在Debian和Ubuntu上,您可以使用以下命令安装库和头文件:
apt install libcgicc5 libcgicc5-dev
但是在CentOS /RHEL上,没有本机软件包。要在其中安装,请下载和运行:
cd /usr/local/src
wget ftp://ftp.gnu.org/gnu/cgicc/cgicc-3.2.19.tar.gz
tar xfz cgicc*.tar.gz
cd cgicc*
./configure — prefix=/usr
make
make install
注意:3.2.19是撰写本文时的最新版本,但是您可能需要在以下位置检查是否有较新的副本:ftp://ftp.gnu.org/gnu/cgicc/。我还使用/usr作为前缀来避免库链接问题。如果愿意,可以随时更改此设置。
一旦安装了cgicc,就可以对其进行编译。请尝试以下示例,该示例接受来自表单的输入并将其显示在浏览器中。
Makefile:
all:
g++ -O3 -s hello.cpp -o hello.cgi
g++ -O3 -s cgicc.cpp -o cgicc.cgi /usr/lib/libcgicc.a
clean:
rm -f hello.cgi cgicc.cgi
cgicc.html:
<!doctype html>
<html lang="en">
<head>
<title>cgicc Test</title>
</head>
<body>
<form method="POST" action="cgicc.cgi">
<label for="name">Name</label>
<input name="name" type="text" value="">
<input name="submit" type="submit" value="Submit">
</form>
</body>
</html>
cgicc.cpp:
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
void set_content_type(string content_type) {
cout << “Content-type: “ << content_type << “\r\n\r\n”;
}
void set_page_title(string title) {
cout << “<title>” << title << “</title>\n”;
}
void h1_text(string text) {
cout << text << “\n”;
}
int main() {
Cgicc cgi;
string name; set_content_type(“text/html”); cout << “<!doctype html>\n”;
cout << “<html lang=\”en\”>\n”;
cout << “<head>\n”;
set_page_title(“cgicc Test”);
cout << “</head>\n”;
cout << “<body>\n”;
cout << “<p>”; // Grab the “name” variable from the form
name = cgi(“name”);
// Check to make sure it isn’t empty.
if (!name.empty()) {
cout << “Name is “ << name << “\n”;
} else {
cout << “Name was not provided.”;
} cout << “</p>\n”;
cout << “</body>\n”;
cout << “</html>”;
return 0;
}
您可能会注意到,我在Makefile中静态链接了cgicc库。尽管不是必需的(您可以用-lcgicc代替),但我更喜欢将要发送的二进制文件静态链接到服务器,以便将执行程序所需的所有内容捆绑在一起。
在此示例中,cgicc库解析POST变量并为我们返回“name”字段。
在此示例中,我没有对输入的POST变量进行转义,而对于生产站点,务必考虑转义问题(尤其是在与数据库进行交互时)。
这仅仅是cgicc能力的冰山一角。您可以在此处阅读完整的文档:https://www.gnu.org/software/cgicc/doc/index.html
性能
如果您编写良好的代码,C++的速度将非常快。 CGI界面确实会使速度变慢,但是即使如此,您仍然可以获得比PHP等解释语言更好的性能。
也就是说,总有改进的空间。在专用或虚拟环境中,您可以使用Apache或Nginx的FastCGI支持来减少程序加载时的小延迟(除非服务器负载很大,否则不明显)。在我的测试中,我从未遇到过速度下降的情况,但是,一个人流量很大的网站将希望研究这些解决方案,以进一步提高性能。
加分项
将C++程序包装在一个小的Docker容器中将很容易。这将为您提供极大的网站托管灵活性。
您还可以通过在程序中包含C /C++ MySQL开发标头来访问MySQL数据库。如果您熟悉将MySQL与PHP结合使用的话,就会发现函数名称非常相似。
您可以包含ImageMagick C++头文件来直接在程序中处理这些图像,而不是生成额外的命令行过程来处理图像。
总结
使用C++构建网站是可行的,尤其是在性能至关重要的情况下。我不建议在博客或个人网站上使用它-可以使用WordPress或类似工具轻松实现。但是,如果您对速度有极高的需求,并且希望在人迹罕至的地方进行编码,请考虑将C++用于您的下一个商业网站项目。