从官方给出的示例中对于 boost::asio::ip::tcp::acceptor 类的使用,是直接使用构造函数进行构造对象,这一种方法用来学习是一个不错的方式。
但是要用它来做项目却是不能够满足我们的需求的,可它有相应的接口,可以让我们更灵活的使用它来做我们的项目。我们可以把这个accptor 的使用拆分开来,就是分成几个步骤来做。这样我们就可以在我们的项目中,在多个函数里面对它进行一步一步的生成。
简单的用法:
1 #include <iostream> 2 3 #include <boost/asio/io_service.hpp> 4 #include <boost/shared_ptr.hpp> 5 #include <boost/shared_array.hpp> 6 #include <boost/make_shared.hpp> 7 #include <boost/function.hpp> 8 #include <boost/bind.hpp> 9 #include <boost/asio/placeholders.hpp> 10 #include <boost/asio/read.hpp> 11 #include <boost/asio/write.hpp> 12 #include <boost/asio/io_service.hpp> 13 #include <boost/asio/ip/tcp.hpp> 14 15 void async_accept(); 16 void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> new_conn, 17 const boost::system::error_code &ec); 18 void async_read(boost::shared_ptr<boost::asio::ip::tcp::socket> conn); 19 void handle_msg( 20 boost::shared_ptr<boost::asio::ip::tcp::socket> conn, 21 boost::shared_array<char> sa_len, 22 const boost::system::error_code &ec, 23 std::size_t bytes_transfered); 24 25 // 这里将这些对象,写为全局的,在实际的代码中,应该是一个类的成员变量或者其他方式存在 26 boost::asio::io_service io_svc; // io service 实例 27 boost::asio::ip::address_v4 lis_ip; // 默认监听本机所有IP 28 boost::asio::ip::tcp::endpoint lis_ep(lis_ip, 20017); 29 boost::asio::ip::tcp::acceptor acceptor(io_svc, lis_ep); 30 31 int main(int argc, char *argv[]) 32 { 33 async_accept(); 34 35 io_svc.run(); 36 37 return 0; 38 } 39 40 void async_accept() 41 { 42 boost::shared_ptr<boost::asio::ip::tcp::socket> new_sock 43 = boost::make_shared<boost::asio::ip::tcp::socket>(boost::ref(io_svc)); 44 acceptor.async_accept(*new_sock, 45 boost::bind(handle_accept, new_sock, boost::asio::placeholders::error) ); 46 } 47 48 void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> new_conn, 49 const boost::system::error_code &ec) 50 { 51 if (ec != 0) 52 { 53 //LOG_INFO(get_logger(), "accept failed: " << ec.message()); 54 std::cout << "accept failed: " << ec.message() << std::endl; 55 return ; 56 } 57 //LOG_INFO(get_logger(), "a new client connected." << new_conn->remote_endpoint()); 58 std::cout << "a new client connected." << new_conn->remote_endpoint() << std::endl; 59 60 async_read(new_conn); 61 62 // 处理下一个连接,每次处理完了之后,需要再次accept。 63 // 否则BOOST 将只处理一次,然后结束监听。 64 // 所以这里可以处理一个情况,就是当你要结束监听的时候,只要在这里return 65 // 那么io_service 的run() 函数就结束监听。但如果有其他的异步操作时, 66 // run() 函数还是会继续运行的。 67 async_accept(); 68 } 69 70 void async_read(boost::shared_ptr<boost::asio::ip::tcp::socket> conn) 71 { 72 static const int PACKAGE_LENGTH = 6; 73 // 数据报文长度为 6个字节 74 boost::shared_array<char> sa_len(new char[PACKAGE_LENGTH]); 75 76 // 回调函数 77 boost::function<void (const boost::system::error_code &, std::size_t)> cb_msg_len; 78 cb_msg_len = boost::bind(handle_msg, conn, sa_len, _1, _2); 79 80 // 异步读,读一个报文的长度,boost::asio::async_read() 函数有个特点, 81 // 它会将这里指定的buffer 缓冲区读满了才会去回调handle_msg 函数, 82 boost::asio::async_read(*conn, 83 boost::asio::buffer(sa_len.get(), PACKAGE_LENGTH), cb_msg_len); 84 85 } 86 87 void handle_msg( 88 boost::shared_ptr<boost::asio::ip::tcp::socket> conn, 89 boost::shared_array<char> sa_len, 90 const boost::system::error_code &ec, 91 std::size_t bytes_transfered) 92 { 93 if (!conn->is_open()) 94 { 95 //LOG_INFO(g_logger, "socket was not opened."); 96 std::cout << "socket was not opened." << std::endl; 97 //handle_dis_connect(conn); 98 return ; 99 } 100 101 if (ec != 0) 102 { 103 if (ec == boost::asio::error::eof) 104 std::cout << "Disconnect from " << conn->remote_endpoint() << std::endl; 105 else 106 std::cout << "Error on receive: " << ec.message() << std::endl; 107 108 //handle_dis_connect(the_conn); 109 return ; 110 } 111 112 // 这里对接收到的数据做处理 113 // ... 114 115 // 处理完了之后,类似accept 的异常调用一样,需要继续调用异步的读数据 116 // 同样的,如果要结束一个连接,正常的结束应该在这里return 调用。 117 // 当然了,使用socket 的close() shut_down() 函数也可以关闭这个连接。 118 async_read(conn); 119 }