boost.asioのTCP/UDP通信時のBufferに関するメモ

boost.asioでTCP/UDP通信をしようと思うと、まずその辺のサンプルコードをとりあえず写経するでしょう。その際、送受信するバッファのためにasioの求めるバッファを使う事になるでしょう。しかも、UDPTCPで別々のバッファを使う事になったり、asio::bufferだったりasio::streambufだったり、そこにboost::arrayを渡していたり・・・。
そこからデータを取ってくる時にもbuffer_castなる謎のキャストをかましたりするんじゃないでしょうか。普通にバイト列を受け取りor送りたいのに!とそのうち思ってくるでしょう、たぶん。私は思ったので解決策をメモしておきます。

解決策は簡単で、任意のバイト列へのポインタとサイズをboost::asio::bufferに渡してあげればいいです。

char byteArray[256];
auto buffer = boost::asio::buffer(byteArray, 256);

このbufferを受信/送信のそれぞれのメソッドの引数に与えてあげれば

//以下、boost::asio::を省略

io_service ios{ 2 };
ip::tcp::socket tcp{ios, ip::tcp::endpoint(ip::address::from_string("127.0.0.1"), 9876)) };
error_code error{};

//受信
read(tcp, buffer, transfer_exactly(256), error);
//送信
write(tcp, buffer, error);

//UDPなら
ip::udp::socket udp{ios, ip::udp::endpoint(ip::address::from_string("127.0.0.1"), 9876) };
ip::udp::endpoint remote{};

//受信
udp.receive_from(buffer, remote, error);
//送信
udp.send_to(buffer, remote, error);

のような感じで任意のバイト列(std::unique_ptr、std::vectorあたり)をバッファとして扱えます。しかも送受信、TCP/UDP関係なく。なんだか不透明さが取り払われたような気分になれます。


他にも、boost::asio::bufferはstd::stringを受け取ることが出来、文字列を送る際はstd::stringを直接入れられます。また、PODタイプを格納したstd::vectorを受け取ることもできます。ちなみに、上のコードではcharの配列を渡す際に配列サイズをわざわざ書いていますが、PODタイプの配列を渡す分にはサイズ指定はなくてもいいです。

char byteArray[256]{};
auto buffer = boost::asio::buffer(byteArray);

std::string str("abcdefg");
auto strbuf = boost::asio::buffer(str);

std::vector<char> cvec = {0, 1, 2, 3, 4};
auto vecbuf = boost::asio::buffer(cvec);

各関数は同時にサイズを受け取ることもできて、あえて送信データの長さより短いサイズを指定してあげれば、データを途中まで転送することもできたりします。

※2018.5.29 bufferをクラスと勘違いしていた部分を修正・・・

参考文献
buffer - 1.67.0