@XiangZhou
2015-08-29T12:08:41.000000Z
字数 4163
阅读 2837
boost.asio echo服务器
从大二开始就对服务器开发,感兴趣,从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 serverint 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;}
service.run()方法在有异步任务的时候是不会退出的,为了我们的服务器能够一直运行,所有必须在异步任务的回调中在添加一个异步任务,为了我可以使用web压力工具测试它,我在echo输出之后就关闭了这个连接,这样我的siege才能工作。
siege 127.0.0.1:8090 -t20s -c100
结果:
Lifting the server siege... done.Transactions: 3834 hitsAvailability: 100.00 %Elapsed time: 19.38 secsData transferred: 3.23 MBResponse time: 0.00 secsTransaction rate: 197.83 trans/secThroughput: 0.17 MB/secConcurrency: 0.21Successful transactions: 3834Failed transactions: 0Longest transaction: 0.02Shortest transaction: 0.00