使用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++用於您的下一個商業網站項目。