とりあえず daytime のクライアント
ほとんどこれの写経
#include <iostream> #include <boost/asio.hpp> int main () { // io_service を介して OS の IO を使う boost::asio::io_service io_service; // ソケットを作る boost::asio::ip::tcp::socket socket(io_service); // 名前解決をする // (ホスト名とサービス名から、 IP とポートを求める) std::cout << "resolving hostname ..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("time.nist.gov", "daytime"); boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve(query)); // つなぐ std::cout << "connecting to " << endpoint << "..." << std::endl; socket.connect(endpoint); // バッファ boost::array<char, 128> buf; while (true) { // エラーコード取得用変数 boost::system::error_code error; // ソケットからの入力をバッファにコピー // (変数 buf の参照と変数 error の参照を渡す) std::size_t len = socket.read_some(boost::asio::buffer(buf), error); // ソケットからの入力が終わったら break; if (error == boost::asio::error::eof) { break; } // 読み込んだデータを std::cout に出力 std::cout.write(buf.data(), len); } // 正常終了 return 0; }
boost::asio::buffer が何故あるのか分からない。
mutable なバッファか const なバッファか型から判断して、 mutable_buffer か const_buffer を返すんだけど、 read_some の中でやっちゃだめなのかなあ。
次に read_some を非同期にしてみる
#include <iostream> #include <boost/asio.hpp> // バッファ boost::array<char, 128> buf; // 読み込んだときに呼ばれる関数 void read_some_handler(const boost::system::error_code& error, std::size_t len) { // 標準出力に出すよ std::cout.write(buf.data(), len); } int main () { // io_service を介して OS の IO を使う boost::asio::io_service io_service; // ソケットを作る boost::asio::ip::tcp::socket socket(io_service); // 名前解決をする // (ホスト名とサービス名から、 IP とポートを求める) std::cout << "resolving hostname ..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("time.nist.gov", "daytime"); boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve(query)); // つなぐ std::cout << "connecting to " << endpoint << "..." << std::endl; socket.connect(endpoint); // ソケットからの入力を非同期で // (変数 buf の参照と関数の参照を渡す) socket.async_read_some(boost::asio::buffer(buf), read_some_handler); // スレッドが終わるのを待つよ io_service.run(); // 正常終了 return 0; }
buf をグローバル変数にした。
buf をローカル変数にして、 boost::bind を使ってみる
#include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> // 読み込んだときに呼ばれる関数 void read_some_handler(const boost::system::error_code& error, boost::array<char, 128> &buf, std::size_t len) { // 標準出力に出すよ std::cout.write(buf.data(), len); } int main () { // io_service を介して OS の IO を使う boost::asio::io_service io_service; // ソケットを作る boost::asio::ip::tcp::socket socket(io_service); // 名前解決をする // (ホスト名とサービス名から、 IP とポートを求める) std::cout << "resolving hostname ..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("time.nist.gov", "daytime"); boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve(query)); // つなぐ std::cout << "connecting to " << endpoint << "..." << std::endl; socket.connect(endpoint); // バッファ boost::array<char, 128> buf; // ソケットからの入力を非同期で // boost::bind を使って read_some_handler の第二引数を buf に束縛する socket.async_read_some(boost::asio::buffer(buf), boost::bind(read_some_handler, _1, buf, _2)); // スレッドが終わるのを待つよ io_service.run(); // 正常終了 return 0; }
でも、実行してみると
$ ./a.out resolving hostname ... connecting to 192.43.244.18:13... 3��hq���ЊP�Њ0+`cϊ0+[
うまくいかない><
うーん
read_some_handler に渡す buf をポインタ渡しにしてみる
#include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> // 読み込んだときに呼ばれる関数 void read_some_handler(const boost::system::error_code& error, boost::array<char, 128> *buf, std::size_t len) { // 標準出力に出すよ std::cout.write(buf->data(), len); } int main () { // io_service を介して OS の IO を使う boost::asio::io_service io_service; // ソケットを作る boost::asio::ip::tcp::socket socket(io_service); // 名前解決をする // (ホスト名とサービス名から、 IP とポートを求める) std::cout << "resolving hostname ..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("time.nist.gov", "daytime"); boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve(query)); // つなぐ std::cout << "connecting to " << endpoint << "..." << std::endl; socket.connect(endpoint); // バッファ boost::array<char, 128> buf; // ソケットからの入力を非同期で // boost::bind を使って第二引数を buf に束縛する socket.async_read_some(boost::asio::buffer(buf), boost::bind(read_some_handler, _1, &buf, _2)); // スレッドが終わるのを待つよ io_service.run(); // 正常終了 return 0; }
実行
$ ./a.out resolving hostname ... connecting to 192.43.244.18:13... 54730 08-09-21 09:44:59 50 0 0 111.4 UTC(NIST) *
おおお。うまくいった
何故だろうか
マニュアル読んだ
Boost: bind.hpp documentation - 1.36.0
boost::ref 使えって書いてあるお(^ω^;
boost::ref 使ってみた
#include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> // 読み込んだときに呼ばれる関数 void read_some_handler(const boost::system::error_code& error, boost::array<char, 128> buf, std::size_t len) { // 標準出力に出すよ std::cout.write(buf.data(), len); } int main () { // io_service を介して OS の IO を使う boost::asio::io_service io_service; // ソケットを作る boost::asio::ip::tcp::socket socket(io_service); // 名前解決をする // (ホスト名とサービス名から、 IP とポートを求める) std::cout << "resolving hostname ..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("time.nist.gov", "daytime"); boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve(query)); // つなぐ std::cout << "connecting to " << endpoint << "..." << std::endl; socket.connect(endpoint); // バッファ boost::array<char, 128> buf; // ソケットからの入力を非同期で // boost::bind を使って第二引数を buf に束縛する socket.async_read_some(boost::asio::buffer(buf), boost::bind(read_some_handler, _1, boost::ref(buf), _2)); // スレッドが終わるのを待つよ io_service.run(); // 正常終了 return 0; }
実行
./a.out resolving hostname ... connecting to 192.43.244.18:13... 54730 08-09-21 09:44:59 50 0 0 111.4 UTC(NIST) *
すげー。うごいたー
boost::bind を使って read_some_handler 自体を要らなくする。
#include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> int main () { // io_service を介して OS の IO を使う boost::asio::io_service io_service; // ソケットを作る boost::asio::ip::tcp::socket socket(io_service); // 名前解決をする // (ホスト名とサービス名から、 IP とポートを求める) std::cout << "resolving hostname ..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("time.nist.gov", "daytime"); boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve(query)); // つなぐ std::cout << "connecting to " << endpoint << "..." << std::endl; socket.connect(endpoint); // バッファ boost::array<char, 128> buf; // ソケットからの入力を非同期で socket.async_read_some( boost::asio::buffer(buf), boost::bind( &std::basic_ostream<char, std::char_traits<char> >::write, boost::ref(std::cout), buf.data(), _2 ) ); // スレッドが終わるのを待つよ io_service.run(); // 正常終了 return 0; }
実行
$ ./a.out resolving hostname ... connecting to 192.43.244.18:13... 54730 08-09-21 10:22:46 50 0 0 237.3 UTC(NIST) *
まじかよー。
書いてある通りにやったら動いた。何でこんなことが可能なんだ。。。
[C++] 次は connect も非同期にしてみる
#include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> void accept_handler(const boost::system::error_code& error, boost::asio::ip::tcp::socket &socket, boost::array<char, 128> &buf) { // ソケットからの入力を非同期で socket.async_read_some( boost::asio::buffer(buf), boost::bind( &std::basic_ostream<char, std::char_traits<char> >::write, boost::ref(std::cout), buf.data(), _2 ) ); } int main () { // バッファ boost::array<char, 128> buf; // io_service を介して OS の IO を使う boost::asio::io_service io_service; // ソケットを作る boost::asio::ip::tcp::socket socket(io_service); // 名前解決をする // (ホスト名とサービス名から、 IP とポートを求める) std::cout << "resolving hostname ..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("time.nist.gov", "daytime"); boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve(query)); // つなぐ std::cout << "connecting to " << endpoint << "..." << std::endl; socket.async_connect( endpoint, boost::bind( accept_handler, _1, boost::ref(socket), boost::ref(buf) ) ); // スレッドが終わるのを待つよ io_service.run(); // 正常終了 return 0; }
でけたー
うーん
難しいなー