使用Apache + knewcode,用傳統C++構建Web網站

一、準備工作

1、編譯器gcc

Linux(建議Ubuntu 14.04 32位版)下,最新版本需下載源代碼自行編譯,地址如下, 
http://gcc.gnu.org/ 
Windows下,可以直接下載編譯版本Mingw,下載地址如下, 
http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/ 
Ubuntu下,如不需要最新版本,可用如下命令安裝, 
sudo apt-get install gcc g++

2、集成開發環境Code::Blocks

跨平臺的開發環境,Windows下和Linux下都可使用,方便調試,下載地址如下, 
http://www.codeblocks.org/downloads/26 
Ubuntu下,可用如下命令安裝, 
sudo apt-get install codeblocks

3、網站平臺Apache

下載地址,http://www.apache.org/ 
Ubuntu下,可用如下命令安裝 
sudo apt-get install apache2

4、支持C++的Apache模塊knewcode

最新版本0.92a版,下載地址如下, 
http://download.csdn.net/detail/zogyzen/9123653 
(在debug目錄下,附帶了適用Windows的Apache2.2.25版) 
非常適用于最低配置的阿里云或騰訊云,預裝32位的Ubuntu 14.04版的服務器。

二、構建Web網站

1、hello world的例子

(1)、頁面hello_world.kc

代碼如下,

<!-- interface語句 --> <!--<%
    #interface<IHelloWorld>;
    #string HelloWorld(#string);
%>--> <!-- load語句 --> <!--<%
    #load $mod = "/bin/hello_world_cpp";
    #interface<IHelloWorld> CreateInf();
    #void FreeInf(#interface);
%>--> <!-- 定義 --> <!--<%
    #string $name = "tom";
    #interface $in = $mod.CreateInf();
%>--> <html> <head> <title><% #print $name; %></title> </head> <body> <!-- 輸出 --> <!--<% #print $in.HelloWorld($name); %>--> </body> </html> <!--<% $mod.FreeInf($in); %>-->


(2)、動態庫hello_world_cpp

hello_world.cpp代碼如下,需要編譯為hello_world_cpp.dll(Windows下)或hello_world_cpp.so(Linux下); 放在網站根目錄的“bin”子目錄下,

#include <iostream> #include <string> using namespace std; #include "common_define.h"  class IHelloWorld
{     
    public: virtual const char* CALL_TYPE HelloWorld(const char*) = 0;
}; class CHelloWorld : public IHelloWorld
{     
    public: virtual const char* CALL_TYPE HelloWorld(const char* s)
    {
        m_s = string("Hello ") + s;         cout << m_s << endl; return m_s.c_str();
    }     virtual ~CHelloWorld() = default; private:     string m_s;
};  extern "C" {
    IHelloWorld& CALL_TYPE CreateInf(void)
    {
        CHelloWorld* hw = new CHelloWorld; return *hw;
    }     
    void CALL_TYPE FreeInf(IHelloWorld* inf)
    {         
        delete dynamic_cast<CHelloWorld*>(inf);
    }
}


2、knewcode簡單介紹

C++一直被詬病為,不善于開發界面程序,不善于開發數據庫程序,不善于開發Web程序等等。 
微軟的DotNet雖然包含了C++,但開發Asp.Net卻不能使用C++(即便能使用,也是托管下的C++,不是標準C++),不過受DotNet啟發,knewcode便孕育而生了。 
knewcode與知名的PHP一樣構建在Apachede平臺上,借力于Apache的穩定與健壯等特性;不過,PHP是純腳本的Web開發平臺,而knewcode則實現了頁面與業務的分離,頁面部分使用傳統的【HTML+JavaScript+CSS】加少量knewcode腳本實現,業務部分則是使用符合傳統C++開發方式,編譯實現。

(1)、knewcode的目錄結構:

【debug】目錄,附帶了適用Windows的Apache2.2.25版,在Windows下將整個knewcode目錄拷貝到D盤根目錄下,執行“D:\knewcode0.92a\StartDebug.bat”,可啟動Apache測試環境; 如果需要正式使用這個平臺,請將Apache注冊為Windows服務;如果需要更改所在目錄,請打開Apache的conf\httpd.conf配置文件,修改相應配置的目錄,“ServerRoot”、“DocumentRoot”、“LoadModule dlib_kc_module”、“dlib_kc_path”; 其它Apache的配置,請詳見Apache的相關文檔。 
【hint_file】目錄,存放提示信息的文件,如果一定要修改的話,請不要增加、修改、刪除字符串中的標志位,如,%1%、%2%、%3%等。 【include】目錄,開放使用的C++頭文件,網站應用的C++動態庫,需要引用“common_define.h”頭文件,并將自定義的函數(全局或成員),定義為“CALL_TYPE”調用約定。 
【lib】目錄,擴展庫目錄,后續版本會有更多的擴展庫,用戶也可自定義擴展程序; 
目前提供數據庫擴展“db”,目前只支持sqlite和postgresql,后續版本會陸續加上Oracle、MySQL、DB2等; 
Web Service擴展“service”,簡單支持soap,尚不支持WSDL;   
服務端會話狀態擴展“session”; 
網絡擴展“net”和通用擴展“util”,功能還很簡單,會逐步完善。 
【modules】目錄,knewcode主體功能的動態庫文件,同時包含了Windows(.dll)和Linux(.so)的版本。 
【sample】目錄,三個例子,本目錄被設置為Apache的網站根目錄; 
src\exam_blog,使用一個HTML5的模板,實現了一個簡單的blog功能的例子,對應index.kc頁面; 
src\hello_world_cpp,簡單網站業務層例子(對應hello_world.kc頁面),和Web Service服務器端例子(對應webservice.kc頁面); 
src\webservice_client(c#),Web service客戶端例子,使用C#編寫。 
【config.xml】配置文件 
Parameters -> logging,日志類型,有debug、info、warning、error四個等級; 
Parameters -> hint_file,提示信息的文件;對應【hint_file】目錄中的文件名; 
Directories -> lib,對應【lib】目錄,“<lib>”標記可直接在頁面腳本中使用,如“#include "<lib>/session/so_session.kc";”;也可添加自定義目錄。 
【kc_apache_mod.dll(或.so)】,Apache模塊文件。 
【kc_fastcgi_mod.exe】,fastcgi程序,可將knewcode配置在IIS7下使用。

(2)、基本腳本介紹

腳本括號:被【<!--<%或<%】和【%>-->或%>】括起來的字符串為knewcode的腳本; 
注釋:腳本中用大括號括起來的為注釋; 
#note和#end-note關鍵字:用于注釋掉HTML文本,如,<!--<% #note %>-->文字<!--<% #end-note %>-->,中間的“文字”將不會在最終的頁面上顯示;

a)、定義語句,包括變量定義,加載動態庫定義,接口定義,包含頁面定義等:

#void、#int、#double、#string、#bool、#interface:數據類型關鍵字,#void只能用于定義無返回值的函數,其余類型可用于定義變量和函數形參;

#true、#false:bool類型的常量值;

函數定義:如,“#void ShowInfo(#int, #interface);”,首先,定義返回值類型,無返回值定義為“#void”,接下來是函數名,最后是用小括號括起來的形參列表;

#load:加載動態庫的語句,如,“#load $mod1 = "/bin/hello_world_cpp";”,可加載“bin”目錄下的“hello_world_cpp”動態庫;不必寫擴展名,Windows下默認擴展名為“.dll”,Linux下默認擴展名為“.so”; 
定義加載動態庫后,要馬上定義該動態庫內包含的函數列表,函數名要與動態庫中的函數名對應; 
一個腳本括號內只能定義一個加載動態庫,不能再包含其他的語法元素; 
 
#interface:定義接口的語句,如,“#interface<IExamBlog>;”,尖括號內為接口的名稱; 
定義接口后,要馬上定義該接口包含的所有函數列表;該函數列表與C++接口定義中的虛函數對應,并且是按順序對應(不是按函數名對應); 
一個腳本括號內只能定義一個接口,不能再包含其他的語法元素;

#include:包含其它頁面的語句,如,“#include "<lib>/session/so_session.kc";”,將把其它頁面的內容包含到當前位置; 
一個腳本括號內如果包含了#include,就只能包含一組#include,不能再包含其他的語法元素;

b)、表達式

運算符:()、+、-、*、/、\、&&、||、!、^、==、!=、<、<=、>、>= 
函數調用:如,“$in.HelloWorld($name);”,首先是接口變量名(或加載動態庫名),接下來是成員提取符(實心點),最后是用小括號括起來的實參列表;返回值可以賦值給變量,也可以打印到頁面上;

c)、結構語句,每個腳本括號內只能有一條語句,并且以分號結束語句。

#print:打印到頁面語句; 
#exit:退出頁面語句; 
#if、#else-if、#else、#end-if:條件分支語句; 
#while、#end-while、#break、#continue:循環語句;

d)、內部變量

$$get["參數名"]:鏈接串中get參數; 
$$post["參數名"]:頁面post參數; 
$$cookie["名稱"]:頁面cookie值; 
$$user["名稱"]:自定義內部變量。

三、構建Web Service服務器端

1、服務器端的例子

(1)、業務部分同hello_world_cpp例子,見“一、1、(2)”;

(2)、頁面webservice.kc

代碼如下,

<!-- interface語句 --> <!--<%
    #interface<IHelloWorld>;
    #string HelloWorld(#string);
%>--> <!-- load語句 --> <!--<%
    #load $mod = "/bin/hello_world_cpp";
    #interface<IHelloWorld> CreateInf();
    #void FreeInf(#interface);
%>--> <!--<% #interface $iWebs = $mod.CreateInf(); %>--> <!--<% #include "<lib>/service/so_webservice.kc"; %>--> <!--<% $mod.FreeInf($iWebs); %>-->


2、客戶端的例子(C#)

代碼如下,

using System; using System.Configuration; using System.Collections.Generic; using System.Text; using System.Data; namespace webservice_client
{     
    // “iWebs”對應服務器端腳本的接口變量名     
    [System.Web.Services.WebServiceBindingAttribute(Name = "WebServiceBase", Namespace = "iWebs")]     
    public class WebServiceBase : System.Web.Services.Protocols.SoapHttpClientProtocol
    {         
        // 客戶端cookie         
        private static System.Net.CookieContainer g_cookies = new System.Net.CookieContainer();         
        // 構造         
        public WebServiceBase()
        {             
            this.Url = ""http://127.0.0.1:8090/webservice.kc"";             
            this.CookieContainer = g_cookies;             
            this.Timeout = 3600 * 1000 * 8;
        }         
        // 函數測試         
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute(Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]         
        public string HelloWorld(string name)
        {             
            return this.CallWebMethod<string>("HelloWorld", new object[] { name }, "");
        }         
        // 執行服務器端方法         
        protected T CallWebMethod<T>(string methodName, object[] parameters, T DefaultValue)
        {         
            try         
            {             
                object[] result = this.Invoke(methodName, parameters);             
                return (T)result[0];
            }             catch (Exception)
            {                 // throw;             }             return DefaultValue;
        }
    }
}
     本文由用戶 zogy 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
     轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
     本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!