雖然有用過libuv,不過Boost asio可能會成為下一代C++的標準配備,還是先熟悉一下。
Boost除了Network之外,還有其他很多功能,不過此次就先以Network作介紹。
它同時支援Sync / Async兩種方式,以下是個範例。
Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <iostream> #include <boost/asio.hpp>
using namespace boost::asio; using namespace boost::system; using namespace std; int main(int argc, char* argv[]) { io_service iosev; ip::tcp::acceptor acceptor(iosev, ip::tcp::endpoint(ip::tcp::v4(), 10000)); char buf[100]; for(;;) { ip::tcp::socket socket(iosev); acceptor.accept(socket); cout << socket.remote_endpoint().address() << endl; error_code ec; size_t len = socket.read_some(buffer(buf, 100), ec); if (ec) { cout << system_error(ec).what() << endl; break; } if (memcmp(buf, "Hello server", len) == 0) { socket.write_some(buffer("Hello client"), ec); if (ec) { cout << system_error(ec).what() << endl; break; } } } return 0; }
|
Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <iostream> #include <boost/asio.hpp> using namespace boost::asio; using namespace boost::system; using namespace std; int main(int argc, char* argv[]) { io_service iosev; ip::tcp::socket socket(iosev); ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 10000); error_code ec; size_t len; socket.connect(ep, ec); if (ec) { cout << system_error(ec).what() << endl; return -1; } char buf[100]; len = socket.write_some(buffer("Hello server"), ec); if (ec) { cout << system_error(ec).what() << endl; return -1; } len = socket.read_some(buffer(buf, 100), ec); if (ec) { cout << system_error(ec).what() << endl; return -1; } cout << buf << endl; return 0; }
|
看起來跟一般的Sample相差無幾,不過優點就是幫忙斃掉了其他不必要的麻煩。例如跨平台的問題,Header dependency之類令人懊惱的小事。不用煩惱為什麼Winsock2.h要放在Windows.h前面這種踳問題了
Async IO Operation
試著把Client用Async IO的方式重寫了一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| include <iostream> #include <boost/asio.hpp> using namespace boost::asio; using namespace boost::system; using namespace std; io_service iosev; ip::tcp::socket socket_(iosev); static const size_t bufLen = 100; char buf[bufLen]; void DoClose() { socket_.close(); } void OnReceive(const error_code& ec, size_t bytes_transferred) { if (ec) { cout << system_error(ec).what() << endl; DoClose(); } else { cout << buf << endl; } } void OnSend(const error_code& ec, size_t bytes_transferred) { if (ec) { cout << system_error(ec).what() << endl; DoClose(); } else { socket_.async_read_some(buffer(buf, bufLen), OnReceive); } } void OnConnect(const boost::system::error_code& ec) { if (ec) { cout << system_error(ec).what() << endl; } else { socket_.async_send(buffer("Hello server"), OnSend); } } int main(int argc, char* argv[]) { ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 10000); socket_.async_connect(ep, OnConnect); iosev.run(); return 0; }
|
因為這段時間都跟libuv打交道,所以隊這樣的程式碼沒有什麼問題。效率不論,跟libuv的主要的差別在於兩點。
- libuv下read_start之後就會一直餵資料給你,直到你手動下read_stop。而asio如果要得到下一次資料的話,需要手動指定下一次讀取的動作。
- libuv read callback function被呼叫的時候,必須手動將資料拷貝到你想儲存的地方,而 asio會主動存到你想要的地方。
其實就是API設計理念不同,沒有好壞之分。只是使用食要小心注意。