[关闭]
@XiangZhou 2015-08-29T20:08:41.000000Z 字数 4163 阅读 2601

基于boost.asio的ECHO服务器

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服务器。

  1. #include <boost/asio.hpp>
  2. #include <boost/bind.hpp>
  3. #include <boost/function.hpp>
  4. #include <boost/bind/placeholders.hpp>
  5. #include <boost/system/system_error.hpp>
  6. #include <boost/enable_shared_from_this.hpp>
  7. #include <boost/noncopyable.hpp>
  8. #include <boost/array.hpp>
  9. #include <iostream>
  10. #include <list>
  11. using namespace boost::asio;
  12. typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
  13. class TestEchoConnection;
  14. typedef boost::shared_ptr<TestEchoConnection> TestEchoConnection_ptr;
  15. typedef std::list<TestEchoConnection_ptr> ConnectionManager;
  16. class TestEchoConnection : public boost::enable_shared_from_this<TestEchoConnection>
  17. , private boost::noncopyable
  18. {
  19. public:
  20. TestEchoConnection(io_service &server, ConnectionManager &connectManager)
  21. : m_server(server)
  22. , m_connectManager(connectManager)
  23. , m_socket(new ip::tcp::socket(m_server))
  24. {
  25. }
  26. ~TestEchoConnection()
  27. {
  28. std::cout << "~TestEchoConnection" << std::endl;
  29. }
  30. ip::tcp::socket& socket()
  31. {
  32. return *m_socket;
  33. }
  34. void start()
  35. {
  36. m_socket->async_read_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handle_read, shared_from_this(),
  37. _1, _2));
  38. }
  39. void stop()
  40. {
  41. m_socket->close();
  42. m_connectManager.remove(TestEchoConnection_ptr(shared_from_this()));
  43. }
  44. private:
  45. void handle_read(const boost::system::error_code &ec, size_t data_size)
  46. {
  47. if (!ec) {
  48. std::cout << "handle_read->data size:" << data_size << std::endl;
  49. m_socket->async_write_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handler_write,
  50. shared_from_this(), _1));
  51. // m_socket->async_read_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handle_read, shared_from_this(),
  52. // _1, _2));
  53. }
  54. else if (ec == error::operation_aborted || ec == error::eof) {
  55. std::cout << "handle_read" << "remove" << std::endl;
  56. stop();
  57. }
  58. }
  59. void handler_write(const boost::system::error_code &ec)
  60. {
  61. if (!ec) {
  62. memset(&m_buffer, 0, sizeof(m_buffer));
  63. // m_socket->async_read_some(buffer(m_buffer), boost::bind(&TestEchoConnection::handle_read, shared_from_this(),
  64. // _1, _2));
  65. if (ec == error::operation_aborted) {
  66. std::cout << "handler_write" << "remove" << std::endl;
  67. stop();
  68. }
  69. }
  70. stop();
  71. }
  72. private:
  73. io_service& m_server;
  74. ConnectionManager& m_connectManager;
  75. socket_ptr m_socket;
  76. boost::array<char, 1029> m_buffer;
  77. };
  78. class TestEchoServer : public boost::enable_shared_from_this<TestEchoServer>
  79. , private boost::noncopyable
  80. {
  81. public:
  82. TestEchoServer(io_service &service, int port)
  83. : m_io_service(service)
  84. , m_endpoint(ip::tcp::v4(), port)
  85. , m_acceptor(m_io_service, m_endpoint)
  86. {
  87. }
  88. ~TestEchoServer()
  89. {
  90. }
  91. void start_accept()
  92. {
  93. m_connect.reset(new TestEchoConnection(m_io_service, m_connectionManager));
  94. m_acceptor.async_accept(m_connect->socket(), boost::bind(&TestEchoServer::handle_accept, shared_from_this(), _1));
  95. }
  96. private:
  97. void handle_accept(const boost::system::error_code &err)
  98. {
  99. if (!err) {
  100. m_connectionManager.push_back(m_connect);
  101. m_connect->start();
  102. }
  103. start_accept();
  104. }
  105. private:
  106. io_service& m_io_service;
  107. ip::tcp::endpoint m_endpoint;
  108. ip::tcp::acceptor m_acceptor;
  109. ConnectionManager m_connectionManager;
  110. TestEchoConnection_ptr m_connect;
  111. };
  112. // echo server
  113. int main()
  114. {
  115. io_service service;
  116. boost::shared_ptr<TestEchoServer> testserver(new TestEchoServer(service, 8090));
  117. // TestEchoServer tesetserver(service, 8090);
  118. // tesetserver.start_accept();
  119. testserver->start_accept();
  120. service.run();
  121. return 0;
  122. }
service.run()方法在有异步任务的时候是不会退出的,为了我们的服务器能够一直运行,所有必须在异步任务的回调中在添加一个异步任务,为了我可以使用web压力工具测试它,我在echo输出之后就关闭了这个连接,这样我的siege才能工作。
  1. siege 127.0.0.1:8090 -t20s -c100

结果:

  1. Lifting the server siege... done.
  2. Transactions: 3834 hits
  3. Availability: 100.00 %
  4. Elapsed time: 19.38 secs
  5. Data transferred: 3.23 MB
  6. Response time: 0.00 secs
  7. Transaction rate: 197.83 trans/sec
  8. Throughput: 0.17 MB/sec
  9. Concurrency: 0.21
  10. Successful transactions: 3834
  11. Failed transactions: 0
  12. Longest transaction: 0.02
  13. Shortest transaction: 0.00
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注