Boost.Asio使用入门
1、概述:Boost.Asio是一個跨平臺的C++庫,用于網絡和底層I/O編程,可以在I/O對象(如socket)上執行同步和異步操作。
2、簡略的過程分析。以socket的連接操作為例:
你的程序中需要至少定義一個io_service對象:boost::asio::io_service io_service。io_service表示程序到操作系統I/O服務的“連接”。
為執行I/O操作,還需要一個I/O對象(通常需要使用io_service構造),如一個TCP套接字:boost::asio::ip::tcp::socket socket(io_service)。
1)同步的連接過程中,發生以下事件序列(對應下面的左圖):
(1)程序通過I/O對象啟動連接操作:socket.connect(server_endpoint);
(2)I/O對象將請求轉發給io_service;
(3)io_service請求操作系統去執行連接操作;
?。?)操作系統將操作結果返回給io_service;
?。?)io_service將操作的(錯誤)結果轉換成boost::system::error_code對象,并回傳給I/O對象;
?。?)如果操作失敗,I/O對象拋出boost::system::system_error異常。
如果是使用以下方式,則只設置錯誤碼,不會拋出異常:
boost::system::error_code ec; socket.connect(server_endpoint, ec);
2)異步的連接過程中,發生以下事件序列(對應下面的中圖和右圖):
?。?)程序通過I/O對象啟動連接操作:socket.async_connect(server_endpoint, your_completion_handler);
your_completion_handler是一個函數(對象),原型:void your_completion_handler(const boost::system::error_code& ec);
?。?)I/O對象將請求轉發給io_service;
?。?)io_service發信號給操作系統,告知它去開始一個異步的連接操作;
一段時間過去... ...注意,在同步的情形下,程序會一直等待連接操作完成,而異步則是先立即返回。
?。?)連接操作完成時,操作系統把結果放在隊列中;
(5)程序必須調用io_service::run()(或類似函數)以取得操作結果。一般在你剛啟動第一個異步操作時就要調用run();
io_service對象未停止(stopped()返回false)且還有未完成的操作時,run()會一直阻塞,否則直接返回。
我的理解(io_service對象未停止時):如果當前有未完成的異步操作且隊列為空,則需要等待,因此run()將阻塞(在Linux下借助pstack可知是阻塞于epoll_wait()或pthread_cond_wait()等)。操作系統完成某個異步操作后,把結果放到隊列并通知應用程序。run()被“喚醒”,從隊列中取出結果并調用相應的回調函數;如果當前沒有未完成的異步操作且隊列為空,表示所有異步操作已經完成,則run()將直接返回;當然,如果當前隊列非空,則run()直接取出結果并調用回調函數。
asio保證了回調函數只會被run()所在線程調用。因此,若沒有run(),回調函數永遠不會被調用。
(6)在run()中io_service將操作結果取出隊列并翻譯成error_code,然后傳遞給your_completion_handler。
3、例子:
// 一個簡單的回顯服務器 #include <iostream> #include <memory> #include <array> #include <boost/asio.hpp> using boost::asio::ip::tcp; // 服務器和某個客戶端之間的“會話”
// 負責處理讀寫事件 class session : public std::enable_shared_from_this<session> { public: session(tcp::socket s) : socket_(std::move(s)) {} void start() { async_read(); } private: void async_read() { auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(data_), // 異步讀 [this, self](const boost::system::error_code &ec, size_t bytes_transferred) // 讀操作完成時回調該函數 { // 捕獲`self`使shared_ptr<session>的引用計數增加1,在該例中避免了async_read()退出時其引用計數變為0 if (!ec) async_write(bytes_transferred); // 讀完即寫 } ); } void async_write(std::size_t length) { auto self(shared_from_this()); boost::asio::async_write(socket_, boost::asio::buffer(data_, length), // 異步寫 [this, self](const boost::system::error_code &ec, size_t) { if (!ec) async_read(); } ); } tcp::socket socket_; // “會話”基于已經建立的socket連接 std::array<char, 1024> data_; }; // 服務器類 // 監聽客戶端連接請求(async_accept)。與某個客戶端建立socket連接后,為它創建一個session class server { public: server(boost::asio::io_service &io_service, short port) : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)), socket_(io_service) { async_accept(); } private: void async_accept() { acceptor_.async_accept(socket_, std::bind(&server::handle_accept, this, std::placeholders::_1)); // 異步accept。socket連接建立后,調用handle_accept() } void handle_accept(const boost::system::error_code &ec) { if (!ec) { std::shared_ptr<session> session_ptr(new session(std::move(socket_))); session_ptr->start(); } async_accept(); // 繼續監聽客戶端連接請求 } tcp::acceptor acceptor_; tcp::socket socket_; }; int main(int argc, char* argv[]) { boost::asio::io_service io_service; server s(io_service, 52014); io_service.run(); return 0; }
參考資料:
http://www.boost.org/
不斷學習中。。。
總結
以上是生活随笔為你收集整理的Boost.Asio使用入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js错误:对象不支持此属性或方法
- 下一篇: wifi路由器重置路由器如何重设尼玛