基于boost.asio的ECHO服务器

26 篇文章 0 订阅
15 篇文章 0 订阅

前言

从大二开始就对服务器开发,感兴趣,从Qt的QTcpServer和QTcpSocket到使用linux的epoll。后来有因为工作搞了一个nginx和php做app后台,后来想找个游戏服务器方面的工作,可是人家嫌你没开发经验,当时我毕业还没一年,能有多少锤子经验。问我熟悉boost.asio库吗,我说知道,没用过,然后就没有然后啦。老老实实做嵌入式开发。

echo服务器基本是学习网络编程里的”Hello world”。所以今天就拿它开刀。

事件驱动

服务器是一个事件驱动的运行形式,那么整个的事件调度就必须有东西来管理,什么时候该可以读,什么时候是能写的,那么就是boost.asio中的io_service类,其是线程安全的,就是多个线程可以共同操作它。
网络编程离不开socket,boost.asio中的ip::tcp::socket是对其的封装,想将其加到事件循环中,就是绑定到一个io_service上,在初始化的时候当成一个参数传递给它。

异步操作

nginx如此高性能得益于其异步操作,其是Reactor模式,数据的读写不是异步的,boost.asio是Proactor模式,数据的读写是异步的,但是看文档你会发现,在linux平台其实现是Reactor,在window上得益于iocp,实现了读写异步。不使用协程的前提下,使用回调来实现,异步操作通知。

代码如下:
TestEchoConnection封装了一个客户连接,TestEchoServer是echo服务器。

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/bind/placeholders.hpp>
#include <boost/system/system_error.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <list>

using namespace boost::asio;

typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;

class TestEchoConnection;

typedef boost::shared_ptr<TestEchoConnection> TestEchoConnection_ptr;

typedef std::list<TestEchoConnection_ptr> ConnectionManager;


class TestEchoConnection : public boost::enable_shared_from_this<TestEchoConnection>
        , private boost::noncopyable
{
public:
    TestEchoConnection(io_service &server, ConnectionManager &connectManager)
        : m_server(server)
        , m_connectManager(connectManager)
        , m_socket(new ip::tcp::socket(m_server))
    {

    }

    ~TestEchoConnection()
    {
        std::cout << "~TestEchoConnection" << std::endl;
    }

    ip::tcp::socket& socket()
    {
        return *m_socket;
    }

    void start()
    {
        m_socket->async_read_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handle_read, shared_from_this(),
                                                                _1, _2));
    }


    void stop()
    {
        m_socket->close();
        m_connectManager.remove(TestEchoConnection_ptr(shared_from_this()));
    }


private:
    void handle_read(const boost::system::error_code &ec, size_t data_size)
    {
        if (!ec) {
            std::cout << "handle_read->data size:" << data_size << std::endl;
            m_socket->async_write_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handler_write,
                                                                     shared_from_this(), _1));
//            m_socket->async_read_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handle_read, shared_from_this(),
//                                                                    _1, _2));


        }
        else if (ec == error::operation_aborted || ec == error::eof) {
            std::cout << "handle_read" << "remove" << std::endl;
            stop();

        }
    }

    void handler_write(const boost::system::error_code &ec)
    {
        if (!ec) {
            memset(&m_buffer, 0, sizeof(m_buffer));
//            m_socket->async_read_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handle_read, shared_from_this(),
//                                                                    _1, _2));
            if (ec == error::operation_aborted) {
                std::cout << "handler_write" << "remove" << std::endl;
                stop();

            }
        }
        stop();
    }




private:
    io_service& m_server;
    ConnectionManager& m_connectManager;
    socket_ptr m_socket;
    boost::array<char, 1029> m_buffer;


};


class TestEchoServer : public boost::enable_shared_from_this<TestEchoServer>
        , private boost::noncopyable
{
public:
    TestEchoServer(io_service &service, int port)
        : m_io_service(service)
        , m_endpoint(ip::tcp::v4(), port)
        , m_acceptor(m_io_service, m_endpoint)
    {

    }

    ~TestEchoServer()
    {

    }

    void start_accept()
    {
        m_connect.reset(new TestEchoConnection(m_io_service, m_connectionManager));
        m_acceptor.async_accept(m_connect->socket(), boost::bind(&TestEchoServer::handle_accept, shared_from_this(), _1));
    }

private:

    void handle_accept(const boost::system::error_code &err)
    {
        if (!err) {
            m_connectionManager.push_back(m_connect);
            m_connect->start();

        }
        start_accept();
    }


private:
    io_service& m_io_service;
    ip::tcp::endpoint m_endpoint;
    ip::tcp::acceptor m_acceptor;
    ConnectionManager m_connectionManager;
    TestEchoConnection_ptr m_connect;

};




// echo server
int main()
{

    io_service service;
    boost::shared_ptr<TestEchoServer> testserver(new TestEchoServer(service, 8090));
//    TestEchoServer tesetserver(service, 8090);
//    tesetserver.start_accept();
    testserver->start_accept();

    service.run();
    return 0;

}

io_service::run()方法在有异步任务的时候是不会退出的,为了我们的服务器能够一直运行,所有必须在异步任务的回调中在添加一个异步任务,为了我可以使用web压力工具测试它,我在echo输出之后就关闭了这个连接,这样我的siege才能工作。

siege 127.0.0.1:8090 -t20s -c100

结果:


Lifting the server siege...      done.
Transactions:               3834 hits
Availability:             100.00 %
Elapsed time:              19.38 secs
Data transferred:           3.23 MB
Response time:              0.00 secs
Transaction rate:         197.83 trans/sec
Throughput:             0.17 MB/sec
Concurrency:                0.21
Successful transactions:        3834
Failed transactions:               0
Longest transaction:            0.02
Shortest transaction:           0.00
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值