John Torjoの本Boost.Asio C ++ Network Programmingの翻訳を続けています。 2番目の章は大きいことが判明したため、2つの部分に分けます。 このパートでは、Boost.Asioの基本について具体的に説明し、2番目のパートでは非同期プログラミングについて説明します。
内容:
- 第1章:Boost.Asioの使用開始
- 第2章:Boost.Asioの基本
- パート1:Boost.Asioの基本
- パート2:非同期プログラミング
- 第3章:エコーサーバー/クライアント
- 第4章:クライアントとサーバー
- 第5章:同期と非同期
- 第6章:Boost.Asio-その他の機能
- 第7章:Boost.Asio-追加トピック
この章では、Boost.Asioを使用して知る必要があることを説明します。 非同期プログラミングについて詳しく説明します。これは、同期よりもはるかに複雑で、はるかに興味深いものです。
ネットワークAPI
このセクションでは、Boost.Asioを使用してネットワークアプリケーションを作成するために知っておく必要があることを示します。
Boost.Asio名前空間
Boost.Asioのすべては
boost::asio
名前空間またはそのサブスペースにあり、それらを考慮してください:
-
boost::asio
:これはすべての主要なクラスと関数が置かれている場所です。 主なクラスはio_service
とstreambuf
です。read, read_at, read_until
などの関数、その非同期コピー、および書き込み関数とその非同期コピーをread, read_at, read_until
示します。 -
boost::asio::ip
:これは、ライブラリのネットワーク部分が存在する場所です。 主なクラスはaddress, endpoint, tcp, udp, icmp
で、主な機能はconnect
とasync_connect
です。boost::asio::ip::tcp::socket
は、boost::asio::ip::tcp
クラス内の単なるtypedef
であるboost::asio::ip::tcp
注意してください。 -
boost::asio::error
:この名前空間には、I / Oルーチンを呼び出すときに表示されるエラーコードが含まれています -
boost::asio::ssl
:この名前空間にはSSLを扱うクラスが含まれています。 -
boost::asio::local
:この名前空間にはPOSIX固有のクラスが含まれます -
boost::asio::windows
:この名前空間にはWindows固有のクラスが含まれます
IPアドレス
IPアドレスを操作するために、Boost.Asioはクラス
ip::address, ip::address_v4
および
ip::address_v6
。
多くの機能を提供します。 最も重要なものは次のとおりです。
-
ip::address(v4_or_v6_address)
:この関数はv4またはv6アドレスをip::address
変換しip::address
-
ip::address:from_string(str)
:この関数は、IPv4アドレス(ピリオドで区切られた)またはIPv6(16進形式)からアドレスを作成します -
ip::address::to_string()
:この関数は、適切な文字列形式でアドレスを返します -
ip::address_v4::broadcast([addr, mask])
:この関数はbroadcast
アドレスを作成します -
ip::address_v4::any()
:この関数は、任意のアドレスを表すアドレスを返します -
ip::address_v4::loopback(), ip_address_v6::loopback()
:この関数はアドレスのループを返します(v4 / v6プロトコルから) -
ip::host_name()
:この関数は、現在のホストの名前を文字列として返します
ほとんどの場合、
ip::address::from_string
使用し
ip::address::from_string
。
ip::address addr = ip::address::from_string("127.0.0.1");
ホスト名に接続する必要がある場合は、読み進めてください。 次のコードは機能しません。
// throws an exception ip::address addr = ip::address::from_string("www.yahoo.com");
エンドポイント
エンドポイントは、ポートと接続アドレスです。 各ソケットタイプには、独自のエンドポイントクラスがあります(例:
ip::tcp::endpoint, ip::udp::endpoint
、および
ip::icmp::endpoint
。
ポート80で
localhost
に接続する場合は、次のように記述する必要があります。
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80);
次の3つの方法でエンドポイントを作成できます。
-
endpoint()
:デフォルトのコンストラクターであり、UDP / ICMPソケットに使用されることがあります -
endpoint(protocol, port)
:新しい接続を受け入れるためにサーバーソケットで一般的に使用されます -
endpoint(addr, port)
:アドレスとポートでエンドポイントを作成します
以下に例を示します。
ip::tcp::endpoint ep1; ip::tcp::endpoint ep2(ip::tcp::v4(), 80); ip::tcp::endpoint ep3( ip::address::from_string("127.0.0.1), 80);
(IPアドレスではなく)ホストに接続する場合は、次を実行する必要があります。
// outputs "87.248.122.122" io_service service; ip::tcp::resolver resolver(service); ip::tcp::resolver::query query("www.yahoo.com", "80"); ip::tcp::resolver::iterator iter = resolver.resolve( query); ip::tcp::endpoint ep = *iter; std::cout << ep.address().to_string() << std::endl;
tcpを必要なソケットのタイプに置き換えることができます。 まず、接続する名前でクエリを作成します。これは、
resolve()
関数を使用して実装できます。 成功すると、少なくとも1つのレコードが返されます。
エンドポイントを受信すると、そこからアドレス、ポート、IPプロトコル(v4またはv6)を取得できます。
std::cout << ep.address().to_string() << ":" << ep.port() << "/" << ep.protocol() << std::endl;
ソケット
Boost.Asioには
ip::tcp, ip::udp
、
ip::icmp
3種類のソケットクラスが含まれており、もちろん拡張されています。 かなり複雑ですが、独自のソケットクラスを作成できます。 それでもこれを行う場合は、
boost/ asio/ip/tcp.hpp
、
boost/asio/ip/udp.hpp
、および
boost/asio/ip/icmp.hpp
。 それらはすべて、内部
typedef
キーワードを持つかなり小さなクラスです。
ip::tcp, ip::udp, ip::icmp
クラスをプレースホルダーと考えることができます。 次のように定義されている他のクラス/関数に簡単にアクセスできます。
- ip :: tcp ::ソケット、ip :: tcp ::アクセプター、ip :: tcp ::エンドポイント、ip :: tcp ::リゾルバー、ip :: tcp :: iostream
- ip :: udp ::ソケット、ip :: udp ::エンドポイント、ip :: udp ::リゾルバー
- ip :: icmp ::ソケット、ip :: icmp ::エンドポイント、ip :: icmp ::リゾルバ
socket
クラスは、対応するソケットを作成します。 常に
io_service
インスタンスを
io_service
ます。
io_service service; ip::udp::socket sock(service) sock.set_option(ip::udp::socket::reuse_address(true));
各ソケット名には
typedef
があり
typedef
。
-
ip::tcp::socket= basic_stream_socket
ip::udp::socket= basic_datagram_socket<ud
p>
ip::icmp::socket= basic_raw_socket
同期機能エラーコード
以下に示すように、すべての同期関数には、例外をスローしたり、エラーコードを返すオーバーロードがあります。
sync_func( arg1, arg2 ... argN); // throws boost::system::error_code ec; sync_func( arg1 arg2, ..., argN, ec); // returns error code
この章の残りの部分では、多くの同期関数について説明します。 物事を単純にするために、エラーコードを返すオーバーロードの表示を省略しましたが、それらは存在します。
ソケット関数
すべての機能はいくつかのグループに分けられます。 ソケットの種類ごとにすべての機能が利用できるわけではありません。 このセクションの最後にあるリストは、どの機能がソケットのどのクラスに属しているかを示します。
すべての非同期関数は即座に応答しますが、同期関数は操作が完了した後にのみ応答することに注意してください。
結合バインディング関数
これらは、アクティブであるかどうかにかかわらず、ソケットに接続または接続し、ソケットを切断して接続要求を行う関数です。
-
assign(protocol,socket)
:この関数は、raw(自然)ソケットをソケットインスタンスに割り当てます。 継承されたコードを使用する場合(つまり、生のソケットが既に作成されている場合)に使用します。 -
open(protocol)
:この関数は、指定されたIPプロトコル(v4またはv6)でソケットを開きます。 主にUDP / ICMPソケットまたはサーバーソケットに使用します。 -
bind(endpoint)
:この関数はこのアドレスに関連付けられています。 -
connect(endpoint)
:この関数はこのアドレスに同期的に接続します。 -
async_connect(endpoint)
:この関数は、このアドレスに非同期的に接続します。 -
is_open()
:ソケットが開いている場合、この関数はtrueを返します。 -
close()
:この関数はソケットを閉じます。 このソケットの非同期操作はすぐに停止し、error::operation_aborted
エラーコードを返します。 -
shutdown(type_of_shutdown)
:この関数は、呼び出しの直後にsend , receive
または両方の操作send , receive
無効にします。 -
cancel()
:この関数は、このソケットのすべての非同期操作をキャンセルします。 このソケットでのすべての非同期操作はすぐに完了し、error::operation_aborted
エラーコードを返します。
以下に小さな例を示します。
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80); ip::tcp::socket sock(service); sock.open(ip::tcp::v4()); sock.connect(ep); sock.write_some(buffer("GET /index.html\r\n")); char buff[1024]; sock.read_some(buffer(buff,1024)); sock.shutdown(ip::tcp::socket::shutdown_receive); sock.close();
読み取り/書き込み機能
これらは、ソケットで入出力を実行する関数です。
非同期関数の場合、ハンドラーには次のシグネチャvoid handler(const boost::system::error_code& e, size_t bytes);
ハンドラーがありますvoid handler(const boost::system::error_code& e, size_t bytes);
。 しかし、機能自体:
-
async_receive(buffer, [flags,] handler)
:この関数は、ソケットからデータを受信する非同期操作を開始します。 -
async_read_some(buffer,handler)
:この関数はasync_receive(buffer, handler)
と同等です。 -
async_receive_from(buffer, endpoint[, flags], handler)
:この関数は、特定のアドレスからのデータの非同期受信を開始します。 -
async_send(buffer [, flags], handler)
:この関数は、バッファーからの非同期データ転送の操作を開始します -
async_write_some(buffer, handler)
:この関数はasync_send(buffer, handler)
と同等です。 -
async_send_to(buffer, endpoint, handler)
:この関数は、バッファから特定のアドレスにデータを非同期的に転送する操作を開始します。 -
receive(buffer [, flags])
:この関数は、バッファ内のデータを同期的に受信します。 この機能は、データが到着し始めるか、エラーが発生するまでブロックされます。 -
read_some(buffer)
:この関数はreceive(buffer)
と同等です。 -
receive_from(buffer, endpoint [, flags])
:この関数は、このバッファーの特定のアドレスからデータを同期的に受信します。 この関数は、データが到着し始めるか、エラーが発生するまでブロックされます。 -
send(buffer [, flags])
:この関数はバッファからデータを同期的に送信します。 データの送信中またはエラーが発生した場合、この機能はブロックされます。 -
write_some(buffer)
:この関数はsend(buffer)
と同等です。 -
send_to(buffer, endpoint [, flags])
:この関数は、バッファからこのアドレスにデータを同期的に転送します。 データの送信中またはエラーが発生した場合、この機能はブロックされます。 -
available()
:この関数は、ブロックせずに同期的に読み取ることができるバイト数を返します。
バッファについては近い将来に説明します。 フラグを見てみましょう。 フラグのデフォルト値は0ですが、組み合わせも可能です。
-
ip::socket_type::socket::message_peek
:このフラグはメッセージのみを調べます。 メッセージが返されますが、次にそれを呼び出すときは、メッセージを読むために再読み取りする必要があります。 -
ip::socket_type::socket::message_out_of_band
:このフラグは帯域外データを処理します。 OOBデータは、通常のデータよりも重要としてマークされたデータです。 OOBデータの説明は、この本の範囲外です。 -
ip::socket_type::socket::message_do_not_route
:このフラグは、ルーティングテーブルを使用せずにメッセージを送信する必要があることを示します。 -
ip::socket_type::socket::message_end_of_record:
このフラグは、データが記録の終了に関するマーカーでマークされていることを示します。 これはWindowsではサポートされていません。
次のコードを作成したことがある場合は、おそらくmessage_peek
を使用しました。
char buff[1024]; sock.receive(buffer(buff), ip::tcp::socket::message_peek ); memset(buff,1024, 0); // re-reads what was previously read sock.receive(buffer(buff) );
以下は、異なるタイプのソケットに対して同期的および非同期的に読み取る命令を与える例です。
- 例1:TCPソケットへの同期読み取りおよび書き込み:
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80); ip::tcp::socket sock(service); sock.connect(ep); sock.write_some(buffer("GET /index.html\r\n")); std::cout << "bytes available " << sock.available() << std::endl; char buff[512]; size_t read = sock.read_some(buffer(buff));
- 例2:UDPソケットへの同期読み取りおよび書き込み:
ip::udp::socket sock(service); sock.open(ip::udp::v4()); ip::udp::endpoint receiver_ep("87.248.112.181", 80); sock.send_to(buffer("testing\n"), receiver_ep); char buff[512]; ip::udp::endpoint sender_ep; sock.receive_from(buffer(buff), sender_ep);
receive_from
を使用してUDPソケットから読み取る場合、前の例に示すように、エンドポイントのデフォルトコンストラクターを使用する必要があることに注意してください。
- 例3:UDPサーバーソケットからの非同期読み取り:
using namespace boost::asio; io_service service; ip::udp::socket sock(service); boost::asio::ip::udp::endpoint sender_ep; char buff[512]; void on_read(const boost::system::error_code & err, std::size_t read_bytes) { std::cout << "read " << read_bytes << std::endl; sock.async_receive_from(buffer(buff), sender_ep, on_read); } int main(int argc, char* argv[]) { ip::udp::endpoint ep( ip::address::from_string("127.0.0.1"), 8001); sock.open(ep.protocol()); sock.set_option(boost::asio::ip::udp::socket::reuse_ address(true)); sock.bind(ep); sock.async_receive_from(buffer(buff,512), sender_ep, on_read); service.run(); }
ソケット管理
これらの関数は、追加のソケットパラメーターで機能します。
-
get_io_service()
:この関数は、io_service
で受け入れられたio_service
インスタンスを返します。 -
get_option(option)
:この関数はソケットパラメーターを返します -
set_option(option)
:この関数はソケットパラメーターを設定します -
io_control(cmd)
:この関数は、ソケットでI / Oコマンドを実行します。
ソケットに取得/設定できる次のパラメーター:
名 定義 種類 broadcast
true
、ブロードキャストメッセージを許可しますブール debug
true
、ソケットレベルのデバッグを許可しますブール do_not_route
true
、ルーティングを防止し、ローカルインターフェイスのみを使用しますブール enable_connection_aborted
true
場合、切断された接続を再接続しますブール keep_alive
true
、keep-alives
送信しkeep-alives
ブール linger
true
、保存されていない場合、ソケットはclose()
だけ遅延します
データブール receive_buffer_size
受信バッファサイズ int
receive_low_watemark
入力ソケットを処理するときの最小バイト数を提供します int
reuse_address
true
場合、ソケットはすでに使用されているアドレスに関連付けられている可能性がありますブール send_buffer_size
送信バッファサイズ int
send_low_watermark
出力ソケットで送信する最小バイト数を提供します。 int
ip::v6_only
true
、使用できるのはIPv6通信のみです。bool
各名前typedef
ソケットまたはクラスの内部typedef
表しtypedef
。 使用方法は次のとおりです。
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80); ip::tcp::socket sock(service); sock.connect(ep); // TCP socket can reuse address ip::tcp::socket::reuse_address ra(true); sock.set_option(ra); // get sock receive buffer size ip::tcp::socket::receive_buffer_size rbs; sock.get_option(rbs); std::cout << rbs.value() << std::endl; // set sock's buffer size to 8192 ip::tcp::socket::send_buffer_size sbs(8192); sock.set_option(sbs);
前の関数が機能するには、ソケットが開いている必要があります。開いていない場合、例外がスローされます。
TCP vs UDPおよびICMP
先ほど言ったように、すべてのソケットクラスですべてのメンバー関数を使用できるわけではありません。 メンバー関数が異なるリストを作成しました。 ここにメンバー関数がない場合、これはすべてのソケットクラスに存在することを意味します。
お名前 TCP UDP ICMP async_read_some
はい - - async_write_some
はい - - async_send_to
- はい はい read_some
はい - - receive_from
- はい はい write_some
はい - - send_to
- はい はい
その他の機能
接続または入力/出力に関連する他の機能:
-
local_endpoint()
:この関数は、ソケットがローカルに接続されている場合にアドレスを返します。 -
remote_endpoint()
:この関数は、ソケットが接続されたリモートアドレスを返します。 -
native_handle()
:この関数はクリーンなソケットを返します。 Boost.Asioでサポートされていないクリーンソケットを操作するための関数を使用する場合にのみ使用してください。 -
non_blocking()
:この関数は、ソケットが非ブロッキングの場合はtrue
返し、そうでない場合はfalse
返しtrue
。 -
native_non_blocking()
:この関数は、ソケットが非ブロッキングの場合はtrue
返し、そうでない場合はfalse
返しtrue
。 ただし、自然なソケットの純粋なAPIを呼び出します。 原則として、これは必要ありません(non_blocking()
常にこの結果をキャッシュします);native_handle()
を直接扱う場合にのみ使用してください。 -
at_mark()
:OOBソケットのデータを読み取る場合、この関数はtrue
返します。 彼女が必要になることはめったにありません。
その他の考慮事項
そして最後に、コピーコンストラクタとoperator=
利用できないため、ソケットインスタンスをコピーできません。
ip::tcp::socket s1(service), s2(service); s1 = s2; // compile time error ip::tcp::socket s3(s1); // compile time error
各インスタンスはリソース(自然ソケット自体)を保存および管理するため、これは非常に理にかなっています。 コピーコンストラクタを使用した場合、最終的には同じソケットの2つのインスタンスがありました。 何らかの方法で所有権を管理する必要があります(1つのコピーに所有権があるか、参照カウントが使用されているか、または他の方法)。 Boost.Asioでは、コピーを禁止するのが慣習でした(コピーを作成する場合は、共有(shared
)ポインターを使用するだけです)。
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr; socket_ptr sock1(new ip::tcp::socket(service)); socket_ptr sock2(sock1); // ok socket_ptr sock3; sock3 = sock1; // ok
ソケットバッファ
ソケットの読み取りまたは書き込みを行う場合、着信データまたは発信データを含むバッファーが必要です。 バッファメモリはI / O操作に耐える必要があります。 I / O操作が継続している間、リリースされるまでスコープ外にならないようにする必要があります。
同期操作の場合は非常に簡単です。 もちろん、buff
はreceive
操作とsend
操作の両方に耐えなければなりません。
char buff[512]; ... sock.receive(buffer(buff)); strcpy(buff, "ok\n"); sock.send(buffer(buff));
また、次のスニペットに示すように、非同期操作ではそれほど単純ではありません。
// very bad code ... void on_read(const boost::system::error_code & err, std::size_t read_ bytes) { ... } void func() { char buff[512]; sock.async_receive(buffer(buff), on_read); }
async_receive()
呼び出した後、buff
はスコープから外れるため、そのメモリは解放されます。 ソケットで実際にデータを取得する場合は、そのデータを自分のものではないメモリにコピーする必要があります。 他のデータのコードを介して解放または再配布できますが、すべてメモリ破損が発生します。
この問題にはいくつかの解決策があります。
- グローバルバッファを使用
- バッファを作成し、操作が完了したら破棄します
- ソケットおよびバッファなどの追加データをサポートする通信オブジェクトを用意します。
グローバル変数が悪いことは誰もが知っているため、最初の解決策はあまり便利ではありません。 また、2つのハンドラーが同じバッファーを使用するとどうなりますか?
2番目のソリューションを実装する方法は次のとおりです。
void on_read(char * ptr, const boost::system::error_code & err, std::size_t read_bytes) { delete[] ptr; } .... char * buff = new char[512]; sock.async_receive(buffer(buff, 512), boost::bind(on_ read,buff,_1,_2));
操作の完了時にバッファを自動的にスコープ外にしたい場合は、shared pointer
使用shared pointer
:
struct shared_buffer { boost::shared_array<char> buff; int size; shared_buffer(size_t size) : buff(new char[size]), size(size) {} mutable_buffers_1 asio_buff() const { return buffer(buff.get(), size); } }; // when on_read goes out of scope, the boost::bind object is released, // and that will release the shared_buffer as well void on_read(shared_buffer, const boost::system::error_code & err, std::size_t read_bytes) {} ... shared_buffer buff(512); sock.async_receive(buff.asio_buff(), boost::bind(on_read,buff,_1,_2));
shared_buffer
クラスには、shared_array <>
インスタンスのコピーであるshared_array <>
が含まれているため、shared_array <>
は存続します。 後者が範囲外になると、shared_array <>
は自動的に折りたたまれます。
Boost.Asioは、操作の完了時に呼び出される終了ハンドラーのコピーを保持するため、これは期待どおりに機能します。 このコピーは、boost::bind
ファンクタであり、shared_buffer
インスタンスのコピーを内部的に保存します。 これは非常にきれいです!
3番目のオプションは、ソケットをサポートし、バッファーなどの追加データを含む通信オブジェクトを使用することです。これは通常正しいソリューションですが、かなり複雑です。 これについては、この章の最後で説明します。
バッファー関数ラッパー
前に見たコードでは、読み取り/書き込み操作用のバッファーが常に必要でした。コードは実際のバッファーのオブジェクトになり、buffer()
を呼び出して関数に渡します。
char buff[512]; sock.async_receive(buffer(buff), on_read
基本的に、クラスにあるバッファはすべてラップされ、Boost.Asioの関数がバッファを反復処理できるようになります。 次のコードを使用しているとします:
sock.async_receive(some_buffer, on_read);
some_buffer
のインスタンスは、ConstBufferSequence
またはMutableBufferSequence
といういくつかの要件を満たしている必要があります(これらについては、Boost.Asioのドキュメントで確認できます)。 これらの要件を満たすために独自のクラスを作成する詳細は非常に複雑ですが、Boost.Asioにはこれらの要件をモデル化するクラスが既に含まれています。 直接アクセスするのではなく、buffer()
関数を使用します。
buffer()
関数で次をラップできると言えば十分です。
- 文字の定数配列
-
void*
および文字サイズ - 文字列
std::string
- 定数配列POD [](PODは古いデータに適しています。つまり、コンストラクターとデストラクターは何もしません)
- 配列
std::vector
任意のPODからのstd::vector
-
boost::array
PODからのboost::array
- 配列
std::array
任意のPODからのstd::array
次のコードが機能しています:
struct pod_sample { int i; long l; char c; }; ... char b1[512]; void * b2 = new char[512]; std::string b3; b3.resize(128); pod_sample b4[16]; std::vector<pod_sample> b5; b5.resize(16); boost::array<pod_sample,16> b6; std::array<pod_sample,16> b7; sock.async_send(buffer(b1), on_read); sock.async_send(buffer(b2,512), on_read); sock.async_send(buffer(b3), on_read); sock.async_send(buffer(b4), on_read); sock.async_send(buffer(b5), on_read); sock.async_send(buffer(b6), on_read); sock.async_send(buffer(b7), on_read);
一般に、ConstBufferSequence
またはMutableBufferSequence
要件を満たすために独自のクラスを作成する代わりに、必要にConstBufferSequence
てバッファーを含むクラスを作成し、mutable_ buffers_1
インスタンスを返すことができます。これは、クラスで行ったことと同じです以前はshared_buffer
。
独立した読み取り/書き込み/接続機能
Boost.Asioは独立したI / O機能を提供します。 私はそれらを4つのグループに分けました。
接続機能
これらの関数は、ソケットまたは終了アドレスを接続します。
-
connect(socket, begin [, end] [, condition])
: ,begin
end
.begin
socket_type::resolver::query
( , « » ). , .condition
, .Iterator connect_condition(const boost::system::error_code & err, Iterator next);
。 , , . -
async_connect(socket, begin [, end] [, condition], handler):
.void handler(const boost::system::error_code & err, Iterator iterator);
。 , ( end ).
:
using namespace boost::asio::ip; tcp::resolver resolver(service); tcp::resolver::iterator iter = resolver.resolve(tcp::resolver::query("www.yahoo.com","80")); tcp::socket sock(service); connect(sock, iter);
,connect
async_connect
, ; .
/
( , ):
-
async_read(stream, buffer [, completion] ,handler)
: . .void handler(const boost::system::error_code & err, size_t bytes);
。 completion .Completion
read
, Boost.Asioasync_read
( , ).size_t completion (const boost::system::error_code& err, size_t bytes_transfered)
. 0, , ; , ,async_read_some
. . -
async_write(stream, buffer [, completion], handler)
: .async_read
. -
read(stream, buffer [, completion])
: .async_read
-
write(stream, buffer [, completion])
: .async_read
. -
async_read(stream, stream_buffer [, completion], handler)
-
async_write(strean, stream_buffer [, completion], handler)
-
write(stream, stream_buffer [, completion])
-
read(stream, stream_buffer [, completion])
- , . , . , Windows.
:
- ( ) ( ).
-
Completion
0 ( ). - .
, '\n':
io_service service; ip::tcp::socket sock(service); char buff[512]; int offset = 0; size_t up_to_enter(const boost::system::error_code &, size_t bytes) { for ( size_t i = 0; i < bytes; ++i) if ( buff[i + offset] == '\n') return 0; return 1; } void on_read(const boost::system::error_code &, size_t) {} ... async_read(sock, buffer(buff), up_to_enter, on_read);
, Boost.Asiocompletion
:
- transfer_at_least(n)
- transfer_exactly(n)
- transfer_all()
:
char buff[512]; void on_read(const boost::system::error_code &, size_t) {} // read exactly 32 bytes async_read(sock, buffer(buff), transfer_exactly(32), on_read);
stream_buffer
Boost.Asio,std::streambuf
. STL , :
io_service service; void on_read(streambuf& buf, const boost::system::error_code &, size_t) { std::istream in(&buf); std::string line; std::getline(in, line); std::cout << "first line: " << line << std::endl; } int main(int argc, char* argv[]) { HANDLE file = ::CreateFile("readme.txt", GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,0); windows::stream_handle h(service, file); streambuf buf; async_read(h, buf, transfer_exactly(256), boost::bind(on_read,boost::ref(buf),_1,_2)); service.run(); }
,async_read
( - ) Windows. 256 . ,on_read
,std::istream
, (std::getline
) .
read_until/async_read_until
:
-
async_read_until(stream, stream_buffer, delim, handler)
: . (delim
). ,std::string
boost::regex
.void handler(const boost::system::error_code & err, size_t bytes);
。 -
async_read_until(stream, stream_buffer, completion, handler)
: , .pair<iterator,bool> completion(iterator begin, iterator end);
,buffers_iterator<streambuf::const_buffers_type>
. , . (begin, end
) . ; ;true
, , ,false
. -
read_until(stream, stream_buffer, delim)
: .async_read_until
.
:
typedef buffers_iterator<streambuf::const_buffers_type> iterator; std::pair<iterator, bool> match_punct(iterator begin, iterator end) { while ( begin != end) if ( std::ispunct(*begin)) return std::make_pair(begin,true); return std::make_pair(end,false); } void on_read(const boost::system::error_code &, size_t) {} ... streambuf buf; async_read_until(sock, buf, match_punct, on_read);
, :
async_read_until(sock, buff, ' ', on_read);
*_at
/ . , / ( ):
-
async_read_at(stream, offset, buffer [, completion], handler)
: ,offset
.handler (const boost::system::error_code& err, size_t bytes);
。buffer()
streambuf
. , Boost.Asioasync_read_at operation
( , ).size_t completion(const boost::system::error_code& err, size_t bytes);
。 0, , , , ,async_read_some_at
. -
async_write_at(stream, offset, buffer [, completion], handler)
: .async_read_at
. -
read_at(stream, offset, buffer [, completion])
: .async_read_at
. -
read_at(stream, offset, buffer [, completion])
: .async_read_at
.
. ; , , . (forward-only
).
128 , 256:
io_service service; int main(int argc, char* argv[]) { HANDLE file = ::CreateFile("readme.txt", GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,0); windows::random_access_handle h(service, file); streambuf buf; read_at(h, 256, buf, transfer_exactly(128)); std::istream in(&buf); std::string line; std::getline(in, line); std::cout << "first line: " << line << std::endl; }
, . . .
皆さんに幸運を! -