• HTTP服务端JSON服务端


    HTTP服务端JSON服务端

    最后更新日期:  2014-5-18

    Author: Kagula

    阅读前提: CMake工具的基本使用

    内容简单介绍:

       CPPCMS是个开源Web开发框架,通过它能够非常easy实现HTTP服务和JSON服务,这里介绍CPPCMS开发环境的搭建。写一个CPPCMS測试程序,它建立HTTP服务,向浏览器返回Hello,World页面。CPPCMS依赖的一些第三方库,其他地方已经介绍怎么Build,所以这里不反复了。

    环境:Windows8.1 64bit、Visual Studio 2013 Professional SP1

    zlib-1.2.8、openssl-1.0.1g、pcre-8.35、icu4c-53_1、  cppcms-1.0.4、python-3.4.0.、CMake2.8.12.2、

    boost 1.55

    搭建CPPCMS开发环境

    CPPCMS依赖zlib、openssl、pcre、icu4c、python和Win SDK等第三方库或工具

             在python官网下载、安装python-3.4.0.amd64.msi,不要忘记在向导中勾选,把python.exe的位置增加到系统的环境变量中。

    我电脑中编译好的库,它们的位置

    zlib

    头文件位置:D:/SDK/zlib-1.2.8;D:SDKzlib-1.2.8uild;

    库文件位置:D:/SDK/zlib-1.2.8/build/Release

    openssl

    头文件位置:D:SDKopenssl-1.0.1ginclude

    库文件位置:D:SDKopenssl-1.0.1gout32dll

    icu4c

             下载http://download.icu-project.org/files/icu4c/53.1/icu4c-53_1-src.zip文件

    打开D:SDKicu4c-53_1-srcicusourceallinoneallinone.sln文件。Build出Release版本号就可以。

    头文件位置:D:SDKicu4c-53_1-srcicuinclude

    库文件位置:;D:SDKicu4c-53_1-srciculib

    pcre

             下载ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.35.zip

             使用CMake工具在D:SDKpcre-8.35uild下生成PCRE.sln文件。使用VisualStudio 2013打开并编译就可以。

    头文件位置:D:/SDK/pcre-8.35;D:SDKpcre-8.35uild;

    库文件位置:D:SDKpcre-8.35uildRelease

    准备好后就能够构建cppcms库了

    从cppcms官网下载cppcms-1.0.4.tar.bz2文件并解压缩到“D:SDKcppcms-1.0.4”,打开cmake gui工具configure后,出现了非常多变量

    加入变量

    CMAKE_INCLUDE_PATH

    类型为filepath

    值为

    D:/SDK/pcre-8.35;D:SDKpcre-8.35uild;D:/SDK/zlib-1.2.8;D:SDKzlib-1.2.8uild;D:SDKicu4c-53_1-srcicuinclude;D:SDKopenssl-1.0.1ginclude

    加入变量

    CMAKE_LIBRARY_PATH

    类型为filepath

    值为D:SDKpcre-8.35uildRelease;D:/SDK/zlib-1.2.8/build/Release;D:SDKicu4c-53_1-srciculib;D:SDKopenssl-1.0.1gout32dll;C:ProgramFiles (x86)Microsoft SDKsWindowsv7.1ALib

             又一次configure后generate。打开新生成的sln文件。BuildSolution有四个选项Debug、MinSizeRel(最小发行版)、Release、RelWithDebInfo(带Debug信息的发行版)。我们这里选Release模式build。

    编译过程中碰到

    [1]zconf.h文件找不到的问题,这个文件在我的D:SDKzlib-1.2.8uild路径下,给它地址,这个问题解决。

    [2]json.cpp 文件 return is_ 代码行通只是, 改为returnbool(is_)就可以,由于Visual Studio 2013(C++11标准)要求istream显式(explicitly)转换bool类型。

    [3]test_formatting.cpp和test_boundary.cpp源代码文件由于出现特殊字符(事实上是文件语言编码的问题)导致无法编译。跳过,由于这两个測试项目不能编译,不影响我们以后使用cppcms库。

    [4]改动D:SDKcppcms-1.0.4oosterooster owidefstream.h文件第44行,

    if(my_base_type::open(convert(s).c_str(),mode)){

    改动为

    if (std::basic_filebuf<CharType,Traits>::open(s, mode)) {

    否则调用CPPCMS的Debug版会挂掉。

    [5]因为CPPCMS的Release版本号application类的main方法std::string实參释放时会出错,所以我把它改成const char *类型。以下三步是详细步骤

    [5-1]“D:SDKcppcms-1.0.4cppcmsapplication.h”文件第298行

    virtual void main(std::string url);

    改动为

    virtual void main(const char* url);

    [5-2]“D:SDKcppcms-1.0.4srcapplication.cpp”文件第200行

    void application::main(std::string  url)

    改动为

    void application::main(const char* url)

    [5-3]“D:SDKcppcms-1.0.4srcurl_dispatcher.cpp”文件第49行

    [6]改动json_rpc_server相关文件。使json服务可用

    [6-1]

    “D:SDKcppcms-1.0.4cppcms pc_json.h”152行

    virtual void main(std::string);

    改为

    virtual void main(const char*);

     [6-2]“D:SDKcppcms-1.0.4src pc_json.cpp”148行

    void json_rpc_server::main(std::string/*unused*/)

    改为

    void json_rpc_server::main(const char*/*unused*/)

    app_->main(match_[select_]);

    改动为

    std::string tmp = match_[select_];

    app_->main(tmp.c_str());

    如今rebuild整个solution, 等待几分钟后,Visual studio 2013提示77个成功,2个失败(刚才说的文件语言编码问题),3个跳过。这样就能够了。Build后的cppcms.dll、cppcms.lib文件在...cppcms-1.0.4uildRelease文件夹下能够找到。

             以下我们用CPPCMS写一个HelloWorld程序

    Hello World

        构建我们的第一个样例时使用了boost库用来把GBK字符串转utf字符串,我计算机的boost库安装路径是“D:SDKoost_1_55_0”。

             在Visual Studio中新建Win32 控制台项目,AdditonalOptions选项Empty Project。

    设置头文件搜索路径

    D:SDKcppcms-1.0.4

    D:SDKcppcms-1.0.4uild

    D:SDKcppcms-1.0.4ooster

    D:SDKcppcms-1.0.4uildooster

    D:SDKoost_1_55_0

    设置库文件搜索路径

    D:SDKcppcms-1.0.4uildoosterRelease

    D:SDKcppcms-1.0.4uildRelease

    D:SDKoost_1_55_0stagelib

    加入链接库cppcms.lib

    复制以下7个动态链接库到你项目目录中。否则会提示找不到这些DLL文件

    D:SDKpcre-8.35uildReleasepcre.dll

    D:SDKzlib-1.2.8uildReleasezlib.dll

    D:SDKcppcms-1.0.4uildReleasecppcms.dll

    D:SDKcppcms-1.0.4uildoosterReleaseooster.dll

    D:SDKicu4c-53_1-srcicuinicuuc53.dll

    D:SDKicu4c-53_1-srcicuinicudt53.dll

    D:SDKicu4c-53_1-srcicuinicuin53.dll

    加入Source.cpp文件。源码清单例如以下

    #include <cppcms/application.h>
    #include <cppcms/applications_pool.h>
    #include <cppcms/service.h>
    #include <cppcms/http_response.h>
    
    #include <boost/locale.hpp>
    
    class hello : public cppcms::application {
    public:
    	hello(cppcms::service &srv) :
    		cppcms::application(srv)
    	{
    	}
    	void main(const char* url);
    };
    
    void hello::main(const char* url)
    {
    	//GBK转utf
    	std::string  utfStr = 
    		boost::locale::conv::to_utf<char>("<h1>中文測试</h1>
    ", "GBK");
    
    	//输出
    	response().out() <<
    		"<html>
    "
    		"<body>
    "
    		<<utfStr<<
    		"</body>
    "
    		"</html>
    ";
    }
    
    
    int main(int argc, char ** argv)
    {
    	try
    	{
    		/*
    		命令行參数为 -c configure.js
    		让CPPCMS读取configure.js里我们的配置信息
    		*/
    		cppcms::service srv(argc, argv);
    
    		//挂载用户的Web服务,application的继承类hello
    		srv.applications_pool().mount(cppcms::applications_factory<hello>());
    
    		//这里堵塞。等待用户请求
    		srv.run();
    	}
    	catch (std::exception const &e)
    	{
    		std::cerr << e.what() << std::endl;
    	}
    }

    加入configure.js文件,源码清单例如以下

    {  
        "service" : {  
            "api" : "http",  
            "port" : 8080  
        },  
        "http" : {  
            "script_names" : [ "/hello" ]  
        }  
    }  

    按[F5]以Debug方式执行就可以。

    如今你能够使用http://localhost:8080/这个地址訪问你的HTTPserver了。

    JSonserver样例

             我測试了以下这个链接中贴出的代码,能够用,可是假设你的測试程序是在Debug模式,你仅仅能调用debug模式编译出来的CPPCMS动态库,假设你是在Release模式。就仅仅能调用Release模式编译出来的CPPCMS动态库。否则会抛出“bad allocation”的错误。

     服务端代码

    #include <cppcms/application.h>
    #include <cppcms/applications_pool.h>
    #include <cppcms/service.h>
    #include <cppcms/http_response.h>
    #include <cppcms/rpc_json.h>
    #include <cppcms/json.h>
    #include <cppcms/mount_point.h>
    #include <map>
    #include <string>
    
    #include <exception>
    #include <iostream>
    
    /*
    标题:測试CPPCMS提供的JSON_RPC服务功能
    来源:
    使用cppcms开发JSON_RPC服务
    http://www.zeuux.com/group/candcplus/bbs/content/55785/
    
    */
    using namespace std;
    using cppcms::rpc::json_rpc_server;
    using cppcms::rpc::json_method;
    
    class calc_service : public json_rpc_server {
    public:
    	calc_service(cppcms::service &srv) : json_rpc_server(srv) {
    		bind("sum",
    			json_method(&calc_service::sum, this), method_role);
    		bind("div",
    			json_method(&calc_service::div, this), method_role);
    	}
    	void sum(int x, int y) {
    		cppcms::json::value v;
    		v["x"] = x;
    		v["y"] = y;
    		v["result"] = x + y;
    		return_result(v);
    	}
    	void div(int x, int y) {
    		if (y == 0) {
    			return_error("Division by zero.");
    		}
    		else {
    			return_result(x / y);
    		}
    	}
    };
    
    class hello_service : public json_rpc_server {
    public:
    	hello_service(cppcms::service &srv) : json_rpc_server(srv) {
    		bind("hello",
    			json_method(&hello_service::hello, this), method_role);
    		bind("hello_all",
    			json_method(&hello_service::hello_all, this), method_role);
    		bind("hello_x",
    			json_method(&hello_service::hello_x, this), method_role);
    	}
    	void hello(string name) {
    		string say = "Hello, " + name + ".";
    		return_result(say);
    	}
    	void hello_all(vector<string> names) {
    		string say = "Hello, ";
    		for (unsigned i = 0; i<names.size(); i++) {
    			say += names[i] + " ";
    		}
    		return_result(say);
    	}
    	void hello_x(cppcms::json::value val) {
    		return_result(val);
    	}
    };
    
    int main(int argc, char ** argv)
    {
    	try {
    		cppcms::service srv(argc, argv);
    
    		srv.applications_pool().mount(
    			cppcms::applications_factory<calc_service>(),
    			cppcms::mount_point("/calc")
    			);
    
    		srv.applications_pool().mount(
    			cppcms::applications_factory<hello_service>(),
    			cppcms::mount_point("/hello")
    			);
    		srv.run();
    	}
    	catch (exception const &e) {
    		cerr << e.what() << endl;
    	}
    	return 0;
    }


    測试服务端代码的html源代码

    <html>
    <body>
        <script type="text/javascript">
            function call() {
    
                var xhr = new XMLHttpRequest();
                xhr.open("post", 'http://localhost:8080/calc');
                // Required by JSON-RPC over HTTP
                xhr.setRequestHeader("Content-Type", "application/json");
    
                // It is better to use real formatter like JSON.js
                x = parseInt(document.getElementById('x').value);
                y = parseInt(document.getElementById('y').value);
                var request = '{"method":"div","params":[' + x + ',' + y + '],"id":1}';
    
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        res = 'Unknown Error';
                        if (xhr.status === 200) {
                            // Don't call eval in real code use some parser
                            var result = eval('(' + xhr.responseText + ')');
                            if (result.error == null) {
                                res = result.result;
                            }
                            else {
                                res = result.error;
                            }
                        }
                        document.getElementById('result').innerHTML = res;
                    }
                }
                xhr.send(request);
                return false;
            }
        </script>
        <form onsubmit="return call();">
            <p>
                <input type="text" id="x" />
                <input type="submit" value="/" />
                <input type="text" id="y" /> =
                <span id="result"></span>
            </p>
        </form>
    </body>
    </html>

    configure.js代码

    {
        "service" : {
            "api" : "http",
            "port" : 8080,
            },
        "http" : {
            "script_names" : [ "/calc","/hello" ]
        }
    }
    


    补充阅读资料

    CPPCMS在Linux下的编译和安装

    http://blog.csdn.net/csfreebird/article/details/6730623

    官网的Hello World样例

    http://cppcms.com/wikipp/en/page/cppcms_1x_tut_hello

    深入学习 CppCMS

    http://remonstrate.wordpress.com/2012/04/09/%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0-cppcms/

    CppCMS和Nginx协同工作

    http://www.cnblogs.com/believeit/archive/2011/09/03/2183531.html

    CppCMS支持文件上传

    http://www.oschina.net/question/565065_66895

    boost库学习随记五 Boost.Locale 之字符转换 gbkutf8 big5 string wstring等

    http://blog.csdn.net/leitianjun/article/details/24658655

    How to Build libiconv with Microsoft VisualStudio

    http://www.codeproject.com/Articles/302012/How-to-Build-libiconv-with-Microsoft-Visual-Studio

    注意,IE6不支持JSON_RPC技术。

  • 相关阅读:
    poj 2892 && 3468
    hdu 2444
    反素数
    poj 2406 && 1961
    Java定时器Timer的使用
    Linux环境下如何生成core文件
    Java异步CompletableFuture的使用
    Java中线程池的使用
    Linux系统添加应用服务进程的守护进程
    C++通过Webbrowser调用JavaScript
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/6973732.html
Copyright © 2020-2023  润新知