使用开源C++项目WebSocketpp构建web服务器

1、WebsocketPP简介

最近需要构建一个本地的服务器程序,处理PHP服务器发来的请求,看到微软的一个开源项目内部用到了这个开源库,于是就试着用了下,效果还好,主要是很容易处理Web请求并返回数据。(C++写程序来请求,然后用C++在WebsocketPP构建服务器处理请求,想怎么定义数据怎么加密都可以,因为都是C++程序,也不用学习PHP,想想就很美好)。

WebsocketPP是一个使用C++编写的开源Web服务器框架,具体实现则是用的大名鼎鼎的boost::asio。ASIO是一个跨平台的网络库,Windows上底层实现使用的是重叠I/O(PS:Windows上socket服务器性能最好的当然是IOCP了),其架构设计如下图:

使用开源C++项目WebSocketpp构建web服务器_第1张图片

ASIO的官方地址:http://think-async.com/Asio/。WebSocketPP的官方地址:http://www.zaphoyd.com/websocketpp/。由于依耐性,使用前你还需要去下载并编译boost库,编译后把对应的目录加入到VS中。

2、使用WebsocketPP

去Github上把压缩包下载下来,里面很多例子可以参考,因为涉及到很多类型(服务器、客户端、请求、返回……)。我也就用了下处理web请求,返回Json数据。

VS新建一个工程,然后把websocketpp这个文件夹都拷贝过去,把所有文件都添加到VS中。添加头文件,创建一个扩展的服务器类……看代码

#include "stdafx.h"
#include 
#include 
#include 
using std::string;
using std::wstring;


struct testee_config : public websocketpp::config::asio {
    // pull default settings from our core config
    typedef websocketpp::config::asio core;

    typedef core::concurrency_type concurrency_type;
    typedef core::request_type request_type;
    typedef core::response_type response_type;
    typedef core::message_type message_type;
    typedef core::con_msg_manager_type con_msg_manager_type;
    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;

    typedef core::alog_type alog_type;
    typedef core::elog_type elog_type;
    typedef core::rng_type rng_type;
    typedef core::endpoint_base endpoint_base;

    static bool const enable_multithreading = true;

    struct transport_config : public core::transport_config {
        typedef core::concurrency_type concurrency_type;
        typedef core::elog_type elog_type;
        typedef core::alog_type alog_type;
        typedef core::request_type request_type;
        typedef core::response_type response_type;

        static bool const enable_multithreading = true;
    };

    typedef websocketpp::transport::asio::endpoint
        transport_type;

    static const websocketpp::log::level elog_level =
        websocketpp::log::elevel::all;
    static const websocketpp::log::level alog_level =
        websocketpp::log::alevel::all;
};

typedef websocketpp::server server;

using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;

// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;

// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
    s->send(hdl, msg->get_payload(), msg->get_opcode());
}

void on_socket_init(websocketpp::connection_hdl, boost::asio::ip::tcp::socket & s) {
    boost::asio::ip::tcp::no_delay option(true);
    s.set_option(option);
}

void on_http(server* s, websocketpp::connection_hdl hdl)
{
	server::connection_ptr con = s->get_con_from_hdl(hdl);
	websocketpp::http::parser::request rt = con->get_request();
	const string& strUri = rt.get_uri();
	const string& strMethod = rt.get_method();
	const string& strBody = rt.get_body();
	const string& strVersion = rt.get_version();
	std::cout<<"接收到一个"<set_body("everything is ok now!");
	con->set_status(websocketpp::http::status_code::value(600));//websocketpp::http::status_code::ok

	websocketpp::http::parser::response rp;
	string strContent = rt.raw();
	rp.consume(strContent.c_str(), strContent.size());

	//if ( strMethod.compare("POST") == 0 )
	{
		websocketpp::http::parser::request r;
		size_t nRet = r.consume(strUri.c_str(), strUri.size());
		int k = 0;
	}
}

int main(int argc, char * argv[]) {
    // Create a server endpoint
//	websocketpp::http::parser::request r;
// 	r.set_uri("http://www.baidu.com");
// 	r.set_method("GET");
// 	r.set_version("HTTP/1.1");
// 	r.set_body("/?s=123");
// 	string str = r.raw();

// 	std::string firefox = "GET / HTTP/1.1\r\nHost: localhost:5000\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0) Gecko/20100101 Firefox/10.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive, Upgrade\r\nSec-WebSocket-Version: 8\r\nSec-WebSocket-Origin: http://zaphoyd.com\r\nSec-WebSocket-Key: pFik//FxwFk0riN4ZiPFjQ==\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nUpgrade: websocket\r\n\r\n";
// 	
// 	size_t n = r.consume(firefox.c_str(), firefox.size());

    server testee_server;

    short port = 1990;
    size_t num_threads = 1;

    if (argc == 3) {
        port = atoi(argv[1]);
        num_threads = atoi(argv[2]);
    }

    try {
        // Total silence
        testee_server.clear_access_channels(websocketpp::log::alevel::all);
        testee_server.clear_error_channels(websocketpp::log::alevel::all);

        // Initialize ASIO
        testee_server.init_asio();
        testee_server.set_reuse_addr(true);

        // Register our message handler
        testee_server.set_message_handler(bind(&on_message,&testee_server,::_1,::_2));

        testee_server.set_socket_init_handler(bind(&on_socket_init,::_1,::_2));
		testee_server.set_http_handler(bind(&on_http, &testee_server, ::_1));
        // Listen on specified port with extended listen backlog
        testee_server.set_listen_backlog(8192);
        testee_server.listen(port);

        // Start the server accept loop
        testee_server.start_accept();

        // Start the ASIO io_service run loop
        if (num_threads == 1) {
            testee_server.run();
        } else {
            typedef websocketpp::lib::shared_ptr thread_ptr;
            std::vector ts;
            for (size_t i = 0; i < num_threads; i++) {
                ts.push_back(websocketpp::lib::make_shared(&server::run, &testee_server));
            }

            for (size_t i = 0; i < num_threads; i++) {
                ts[i]->join();
            }
        }

    } catch (websocketpp::exception const & e) {
        std::cout << "exception: " << e.what() << std::endl;
    }
}
 
  

on_http就是处理web请求的回调,在这里我们可以根据请求名称来响应处理。const string& strUri = rt.get_uri();获取的就是请求的名称,比如设置服务器端口号为1200,请求:localhost:1200/hello,那么strUri就是/hello,也就是说我们可以根据字符串的匹配来处理不同的请求名称。还有就是POST/GET请求,const string& strMethod = rt.get_method()获取的就是请求方法,POST对应的strMethod =“POST”,GET对应的就是"GET"。请求的数据,const string& strBody = rt.get_body(),只有POST请求才可能有发送的数据,GET请求时这里为空。const string& strVersion = rt.get_version()获取的是HTTP的版本号,通常是1.1。

con->set_body("everything is ok now!");con->set_status(websocketpp::http::status_code::value(600));这两句是设置返回数据和返回码。

设置服务器监听端口testee_server.listen(port),端口号被占用时,开启服务器会失败,如何捕捉呢?在catch (websocketpp::exception const & e)中。


吐槽下CSDN的文章编辑器,真是垃圾。格式设置好痛苦,我复制文字后得粘贴到记事本里去掉格式然后再复制粘贴回来。

下载源代码:http://download.csdn.net/detail/mfcing/9313755(VS2010工程)


 
  
 
  


你可能感兴趣的:(开源)