to myself 的分类学习日志

做自己想做的事
posts - 232, comments - 6, trackbacks - 0, articles - 0

cpp-netlib之async_server解析

Posted on 2013-07-15 16:29 kongkongzi 阅读(1722) 评论(2)  编辑 收藏 引用 所属分类: c++ network library
cpp-netlib:
参考:
1. http://cpp-netlib.org/
2. https://github.com/cpp-netlib/
3. http://github.com/cpp-netlib/


解析版本: cpp-netlib-0.9.4
注:使用的boost版本为boost_1_53_0。 若使用boost_1_46_1在Windows上编译会出现错误。


测试代码
testAsyncServer.cpp
#include "CommonPrecomp.h"
#include "RequestHandler.h"
#include "RequestHandlerFactory.h"
#include <string>
#include <iostream>

struct test_handler {
    /* when there are many request at the same time, can put the request into a queue, then let another thread process it.
     * or maybe need to call http::client to connect to other server, and get response.
     
*/ 
    void operator()(const server::request &request, server::connection_ptr connection)
    {
        request_handler_ptr request_handler_ = request_handler_factory::get_mutable_instance().create();
        return request_handler_->start(request, connection);
    }
};


int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " address port" << std::endl;
        return 1;
    }

    try {
        test_handler handler;
        utils::thread_pool thread_pool_(2);
        server instance(argv[1], argv[2], handler, thread_pool_);
        instance.run();
    }
    catch (std::exception &e) {
        std::cerr << e.what() << std::endl;
        return 1;
    }

    return 0;
}

CommonPrecomp.h
#ifndef _COMMON_PRECOMP_H_
#define _COMMON_PRECOMP_H_

#include <boost/shared_ptr.hpp>
#include <boost/network/protocol/http/server.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/serialization/singleton.hpp>

namespace http = boost::network::http;
namespace utils = boost::network::utils;

struct test_handler;
typedef boost::network::http::async_server<test_handler> server;

#endif // _COMMON_PRECOMP_H_

CommonPrecomp.cpp
#include "CommonPrecomp.h"

RequestHandler.h
#ifndef _REQUEST_HANDLER_H_
#define _REQUEST_HANDLER_H_


class request_handler
{
public:
    struct is_content_length {
        template <class Header>
        bool operator()(Header const & header) {
            return boost::iequals(header.name, "content-length");
        }
    };

    request_handler();
    ~request_handler();

    void start(const server::request &request, server::connection_ptr connection);

    void read_callback(server::connection::input_range input, boost::system::error_code const & ec, std::size_t bytes_transferred, server::connection_ptr connection);

    void write_callback(boost::system::error_code const & ec);

private:
    std::string uri_;
    std::string content_;
    std::size_t content_length_;
    std::size_t read_content_length_;

private:
    static server::response_header common_headers[3];
    static std::string bad_request;
};

typedef boost::shared_ptr<request_handler> request_handler_ptr;


#endif // _REQUEST_HANDLER_H_

RequestHandler.cpp
#include "CommonPrecomp.h"
#include "RequestHandler.h"
#include "RequestHandlerFactory.h"

request_handler::request_handler()
: uri_()
, content_()
, content_length_(0)
, read_content_length_(0)
{
    std::cout << "request_handler constructor!" << std::endl;
}

request_handler::~request_handler()
{
    std::cout << "request_handler destructor!" << std::endl;
}

void request_handler::start(const server::request &request, server::connection_ptr connection)
{
    if (request.method == "POST") 
    {
        server::request::headers_container_type::iterator found =
            boost::find_if(request.headers, is_content_length());
        if (found == request.headers.end()) 
        {
            connection->set_status(server::connection::bad_request);
            connection->set_headers(boost::make_iterator_range(common_headers, common_headers+3));
            connection->write(bad_request, boost::bind(&request_handler::write_callback, this, _1));
            return;
        }

        uri_ = http::destination(request);
        content_length_ = boost::lexical_cast<std::size_t>(found->value);

        connection->read(boost::bind(&request_handler::read_callback, this, _1, _2, _3, _4));
        return;
    } 
    else 
    {
        connection->set_status(server::connection::bad_request);
        connection->set_headers(boost::make_iterator_range(common_headers, common_headers+3));
        connection->write(bad_request, boost::bind(&request_handler::write_callback, this, _1));
    }
}

void request_handler::read_callback(server::connection::input_range input, boost::system::error_code const & ec, std::size_t bytes_transferred, server::connection_ptr connection)
{
    if (ec)
    {
        std::cerr << "Error: " << ec << std::endl;
        // todo others.
        return;
    }

    read_content_length_ += bytes_transferred;
    content_ += std::string(input.begin(), input.end());
    if (read_content_length_ < content_length_)
    {
        connection->read(boost::bind(&request_handler::read_callback, this, _1, _2, _3, _4));
        return;
    }

    if ("/videoProcessing/start" == uri_)
    {
        // todo: decode the body(content) by creating a message of application logic layer
        std::string response_body = "<Message Code=\"0000\" Descript=\"OK.\"></Message>";

        std::vector<server::response_header> headers(common_headers, common_headers+3);
        headers[2].value = boost::lexical_cast<std::string>(response_body.size());
        connection->set_status(server::connection::ok);
        connection->set_headers(boost::make_iterator_range(headers.begin(), headers.end()));
        connection->write(response_body, boost::bind(&request_handler::write_callback, this, _1));
    }
    else
    {
        connection->set_status(server::connection::bad_request);
        connection->set_headers(boost::make_iterator_range(common_headers, common_headers+3));
        connection->write(bad_request, boost::bind(&request_handler::write_callback, this, _1));
    }
}

void request_handler::write_callback(boost::system::error_code const & ec) 
{
    request_handler_factory::get_mutable_instance().destroy(this);
}


server::response_header request_handler::common_headers[3] = {
    {"Connection","close"}
    ,{"Content-Type", "text/plain"}
    ,{"Content-Length", "0"}
};

std::string request_handler::bad_request("Bad Request.");


RequestHandlerFactory.h
#ifndef _REQUEST_HANDLER_FACTORY_H_
#define _REQUEST_HANDLER_FACTORY_H_

#include "RequestHandler.h"

class request_handler_factory : public boost::serialization::singleton<request_handler_factory>
{
public:
    request_handler_ptr create();
    void destroy(request_handler* handler);

    ~request_handler_factory();

private:
    std::list<request_handler_ptr> request_handler_lst;
};


#endif // _REQUEST_HANDLER_FACTORY_H_

RequestHandlerFactory.cpp
#include "CommonPrecomp.h"
#include "RequestHandlerFactory.h"
#include "RequestHandler.h"

request_handler_factory::~request_handler_factory()
{
}

request_handler_ptr request_handler_factory::create()
{
    request_handler_ptr request_handler_(new request_handler());
    request_handler_lst.push_back(request_handler_);
    return request_handler_;
}

void request_handler_factory::destroy(request_handler* handler)
{
    for (std::list<request_handler_ptr>::iterator iter = request_handler_lst.begin(); 
        iter != request_handler_lst.end(); iter++)
    {
        if (iter->get() == handler)
        {
            request_handler_lst.erase(iter);
            return;
        }
    }
}


图1:cppnetlib-asio-async_server.jpg







Feedback

# re: cpp-netlib之async_server解析  回复  更多评论   

2015-06-08 17:35 by linkthaha
博主你好感谢你的这篇博客,我有个问题想请教你一下。
我试了一下用客户端和这个async server进行通信发现会出错:
提示:invalid version part.用官方的例子也是这种情款,想请问一下你有没有遇到过这种情款,又或者要怎么和这个服务端进行通信

# re: cpp-netlib之async_server解析  回复  更多评论   

2015-06-23 10:46 by kongkongzi
@linkthaha
使用“cpp-netlib之async_client解析: http://www.cppblog.com/toMyself/archive/2013/07/15/201825.html” 里的客户端可以,没遇到你说的问题,检查一下用的 cpp-netlib和boost版本是不是对的。

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理