boost库websocket服务器

boost库websocket服务器

基于boost标准C++库,使用协程和beast实现子协议websocket服务器。作为初学者实现内容也比较简单,不做过多的解释,就直接上代码了。

//------------------------------------------------------------------------------
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include <boost/beast/websocket.hpp>
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>


namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>

using namespace boost::asio;
using namespace boost::placeholders;
//------------------------------------------------------------------------------
// Report a failure
void fail(beast::error_code ec, char const* what)
{
    std::cerr << what << ": " << ec.message() << "\n";
}

template<class Body, class Allocator>


void do_session(
	net::io_context& ioc,
    websocket::stream<beast::tcp_stream>& ws,
	http::request<http::string_body> const& req,
    net::yield_context yield)
{
    beast::error_code ec;
	std::string protocol;
    deadline_timer timer(ioc);
	timer.expires_from_now(boost::posix_time::seconds(1));
	
	protocol.assign(req.target().begin(), req.target().end());
    if (protocol.empty()){
		return ;
	}	
    // Set suggested timeout settings for the websocket
    ws.set_option(websocket::stream_base::timeout::suggested(beast::role_type::server));

    // Set a decorator to change the Server of the handshake
	ws.set_option(websocket::stream_base::decorator(
		[protocol](websocket::response_type& res)
		{
			res.set(http::field::server, protocol);
		}));

    // Accept the websocket handshake
    ws.async_accept(req, yield[ec]);	
    if(ec) {
        return fail(ec, "accept");
	}
	if(0 == protocol.compare("/aa/lalala")) {
		for(;;)
		{
			// This buffer will hold the incoming message
			beast::flat_buffer buffer;

			ws.async_write(boost::asio::buffer("------- send lalala -------"), yield[ec]);
			if(ec == websocket::error::closed) {
				break;
			}
			if(ec){
				return fail(ec, "write"); 
			}
			timer.async_wait(yield[ec]);
		}		
	} else if(0 == protocol.compare("/aa/gagaga")) {
		for(;;)
		{
			// This buffer will hold the incoming message
			beast::flat_buffer buffer;

			ws.async_write(boost::asio::buffer("------- send gagaga-------"), yield[ec]);
			if(ec == websocket::error::closed) {
				break;
			}
			if(ec){
				return fail(ec, "write"); 
			}
			timer.async_wait(yield[ec]);
		}		
	} else if(0 == protocol.compare("/aa/hahaha")) {
		for(;;)
		{
			// This buffer will hold the incoming message
			beast::flat_buffer buffer;

			ws.async_write(boost::asio::buffer("------- send hahaha -------"), yield[ec]);
			if(ec == websocket::error::closed) {
				break;
			}
			if(ec){
				return fail(ec, "write"); 
			}
			timer.async_wait(yield[ec]);
		}
	} else {
		return ;
	}
}


// Accepts incoming connections and launches the sessions
void
do_listen(
    net::io_context& ioc,
    tcp::endpoint endpoint,
    net::yield_context yield)
{
    beast::error_code ec;

    // Open the acceptor
    tcp::acceptor acceptor(ioc);
    acceptor.open(endpoint.protocol(), ec);
    if(ec)
        return fail(ec, "open");

    // Allow address reuse
    acceptor.set_option(net::socket_base::reuse_address(true), ec);
    if(ec)
        return fail(ec, "set_option");

    // Bind to the server address
    acceptor.bind(endpoint, ec);
    if(ec)
        return fail(ec, "bind");

    // Start listening for connections
    acceptor.listen(net::socket_base::max_listen_connections, ec);
    if(ec)
        return fail(ec, "listen");

    for(;;)
    {
        tcp::socket socket(ioc);
        acceptor.async_accept(socket, yield[ec]);
        if(ec) {
            fail(ec, "accept");
        } else {
			beast::flat_buffer buffer;
			http::request<http::string_body> req;
			
			http::async_read(socket, buffer, req, yield[ec]);
			// 查看是否是WebSocket升级请求
			if(websocket::is_upgrade(req))
			{
					boost::asio::spawn(
						acceptor.get_executor(),
						std::bind(
							&do_session,
							std::ref(ioc),
							websocket::stream<beast::tcp_stream>(std::move(socket)),
							std::ref(req),
							std::placeholders::_1));
			}
		}
	}
}

int main(int argc, char* argv[])
{
    // Check command line arguments.
    if (argc != 4)
    {
        std::cerr <<
            "Usage: http-server-coro <address> <port> <doc_root> <threads>\n" <<
            "Example:\n" <<
            "    http-server-coro 0.0.0.0 8080 1\n";
        return EXIT_FAILURE;
    }
    auto const address = net::ip::make_address(argv[1]);
    auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
    auto const threads = std::max<int>(1, std::atoi(argv[3]));

    // The io_context is required for all I/O
    net::io_context ioc{threads};

    // Spawn a listening port
    boost::asio::spawn(ioc,
        std::bind(
            &do_listen,
            std::ref(ioc),
            tcp::endpoint{address, port},
            std::placeholders::_1));
	
    // Run the I/O service on the requested number of threads
    std::vector<std::thread> v;
    v.reserve(threads - 1);
    for(auto i = threads - 1; i > 0; --i)
        v.emplace_back(
        [&ioc]
        {
            ioc.run();
        });
    ioc.run();

    return EXIT_SUCCESS;
}

编译:

$:g++ -g -std=gnu++11 -o server websocket_server_coro.cpp -I/websocket/boost_1_73_0/  -L/websocket/boost_1_73_0/stage/lib  -lboost_context -lboost_coroutine -lboost_chrono -lpthread

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值