John Torjoの本Boost.Asio C ++ Network Programmingの翻訳を続けています。
内容:
- 第1章:Boost.Asioの使用開始
- 第2章:Boost.Asioの基本
- 第3章:エコーサーバー/クライアント
- 第4章:クライアントとサーバー
- 第5章:同期と非同期
- 第6章:Boost.Asio-その他の機能
- 第7章:Boost.Asio-追加トピック
この章では、Boost.Asioの追加トピックについて説明します。 毎日これを使用することはまずありませんが、これを知るための場違いではありません。
- デバッグが失敗した場合、Boost.Asioがこれに役立つことがわかります。
- SSLを使用する必要がある場合は、Boost.Asioが提供するものをご覧ください
- 特定のOC向けのアプリケーションを作成している場合は、Boost.Asioの追加機能をご覧ください
Asio vs Boost.Asio
Boost.Asioの作成者は、Asioのサポートも提供しました。 このライブラリにはAsio(Boostではない)とBoost.Asioの2つのフレーバーが付属しているため、Asioと考えることができます。 著者は、アップデートが最初にAsioに表示され、Boostディストリビューションに定期的に追加されると主張しています。
一言で言えば、違いは次のとおりです。
- Asioは
asio::
の名前空間で定義され、Boost.Asioはboost::asio::
定義されます - Asioのヘッダーファイルは
asio.hpp
、asio.hpp
boost/asio.hpp
です。 - Asioには、スレッドを開始するための独自のクラスがあります(
boost::thread
と同等) - Asioは、エラーコードのクラスを提供します(
asio::error_code
代わりにasio::error_code
boost::system::error_cod
およびasio::system_error
boost::system::system_error
代わりにasio::system_error
boost::system::system_error
)
Asioの詳細については、 こちらをご覧ください 。
どちらのオプションを選択するかは、自分で決める必要があります。 個人的にはBoost.Asioが好きです。 選択する際に考慮すべき事項を次に示します。
- Asioの新しいバージョンは、Boost.Asioの新しいバージョンよりも頻繁にリリースされます(新しいBoostディストリビューションはめったにリリースされません)
- Asioは純粋にヘッダーです(一方、Boost.Asioの一部は、コンパイルに必要な他のBoostライブラリに依存します)
- AsioとBoost.Asioはどちらも完全に開発されているため、新しいAsioリリースの機能を使用したくない場合は、Boost.Asioが非常に優れた代替手段となります。特に、他のBoostライブラリは自由に使用できます。
1つのアプリケーションでAsioとBoost.Asioを使用できますが、これを行うことはお勧めしません。 これは意図的に機能しない場合があります。この場合、たとえば、Asioを使用し、一部のサードパーティライブラリがBoost.Asioを使用する場合、またはその逆の場合、すべてがうまくいきます。
デバッグ
一般に、同期アプリケーションのデバッグは、非同期アプリケーションのデバッグよりも簡単です。 同期アプリケーションの場合、ブロックされた場合は、デバッグを開始して、それが発生した場所の画像を取得するだけです(同期は順次を意味します)。 ただし、非同期でプログラムを作成する場合、イベントは連続して発生しないため、エラーが発生した場合、それをキャッチするのは非常に困難です。
これを避けるために、まず第一に、あなたはコルーチンで非常に良いはずです。 プログラムが正しく実装されていれば、実際には問題はまったくありません。
非同期プログラミングの場合にのみ、Boost.Asioが支援を提供します。 BOOST_ASIO_ENABLE_HANDLER_TRACKINGマクロが
BOOST_ASIO_ENABLE_HANDLER_TRACKING
いる場合、
BOOST_ASIO_ENABLE_HANDLER_TRACKING
ハンドラーを追跡できます。 その場合、Boost.Asioは、時間、非同期操作、およびそれに関連する終了ハンドラーを記録することにより、標準エラー出力ストリームへの情報の出力を促進します。
ハンドラ追跡情報
情報を理解するのは簡単ではありませんが、それでも非常に便利です。 Boost.Asioの出力は次を生成します。
@asio|<timestamp>|<action>|<description>.
最初のタグは常に
@asio
、他のソースが標準エラーストリーム(
std::cerr
と同等)に書き込む場合に、Boost.Asioからのメッセージを簡単にフィルタリングするために使用できます。
timestamp
インスタンスは、1970年1月1日UTCから開始する秒とマイクロ秒でカウントされます。
action
インスタンスは次のいずれかです。
-
>n
:番号nのハンドラーを入力するときに使用されます。description
インスタンスには、ハンドラーに渡される引数が含まれます。 -
<n
:ハンドラー番号nが閉じているときに使用されます。 -
!n
:例外のためにハンドラnを終了するときに使用されます。 -
~n
:番号nのハンドラーが呼び出しなしで破棄されるときに使用されます。 おそらく、io_service
インスタンスio_service
破棄されるのが早すぎる(nが呼び出される前に)ためです。 -
n*m
:nハンドラーがmという番号の最終ハンドラーで新しい非同期操作を作成するときに使用されます。 開始後、開始された非同期操作がdescription
インスタンスに表示されます。 最終ハンドラーは、>m(start)
および<m(end)
が表示されたときに呼び出されます。 -
n
:番号nのハンドラーがdescription
表示される操作(close
操作またはcancel
操作のいずれか)を実行するときに使用されdescription
。 通常、それらは無視しても問題ありません。
n = 0の場合、すべてのハンドラーは外部(非同期)で実行されます。通常、最初の操作(操作)がいつ実行されるか、またはシグナルを操作してシグナルがトリガーされるかがわかります。
コードにエラーがあるときに発生する
!n
や〜nなどのメッセージに注意する必要があります。 最初のケースでは、非同期関数は例外をスローしなかったため、例外はユーザーがスローする必要があります。最終ハンドラーを終了するときに例外を許可しないでください。 後者の場合、呼び出されたすべてのハンドラーが完了する前に、おそらく
io_service
インスタンスを破棄しすぎた
io_service
ます。
例
サポート情報の例を示すために、第6章の例を修正します。
boost/asio.hpp
オンにする前に、追加の
#define
追加する
boost/asio.hpp
です。
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING #include <boost/asio.hpp> ...
また、ユーザーがログインし、クライアントの最初のリストを受け取ったときにコンソールをダンプします。 結論は次のとおりです。
@asio|1355603116.602867|0*1|socket@008D4EF8.async_connect @asio|1355603116.604867|>1|ec=system:0 @asio|1355603116.604867|1*2|socket@008D4EF8.async_send @asio|1355603116.604867|<1| @asio|1355603116.604867|>2|ec=system:0,bytes_transferred=11 @asio|1355603116.604867|2*3|socket@008D4EF8.async_receive @asio|1355603116.604867|<2| @asio|1355603116.605867|>3|ec=system:0,bytes_transferred=9 @asio|1355603116.605867|3*4|io_service@008D4BC8.post @asio|1355603116.605867|<3| @asio|1355603116.605867|>4| John logged in @asio|1355603116.606867|4*5|io_service@008D4BC8.post @asio|1355603116.606867|<4| @asio|1355603116.606867|>5| @asio|1355603116.606867|5*6|socket@008D4EF8.async_send @asio|1355603116.606867|<5| @asio|1355603116.606867|>6|ec=system:0,bytes_transferred=12 @asio|1355603116.606867|6*7|socket@008D4EF8.async_receive @asio|1355603116.606867|<6| @asio|1355603116.606867|>7|ec=system:0,bytes_transferred=14 @asio|1355603116.606867|7*8|io_service@008D4BC8.post @asio|1355603116.607867|<7| @asio|1355603116.607867|>8| John, new client list: John
各行を分析します。
- ハンドラー1を作成する
async_connect
を導入します(この場合、全員がtalk_to_svr::step
処理します) - ハンドラー1が呼び出されます(サーバーへの接続に成功した後)
- ハンドラー1は
async_send
呼び出し、ハンドラー2を作成します(ここでは、サーバーにログインしてメッセージを送信します) - ハンドラー1が閉じます
- ハンドラー2が呼び出され、11バイトを送信します(
login John
) - ハンドラー2は、ハンドラー3を作成する
async_receive
呼び出します(サーバーがログインメッセージに応答するのを待ちます) - ハンドラー2が閉じます
- ハンドラー3が呼び出され、9バイトを取得します(
login ok
) - ハンドラー3は
on_answer_from_server
リダイレクトしon_answer_from_server
(ハンドラー4が作成されます) - ハンドラー3が閉じます
- ハンドラー4が呼び出され、
John logged in
たダンプに書き込みJohn logged in
- ハンドラー4は、
ask_clients
を書き込む別のstep
(ハンドラー5)を開始します - ハンドラー4が閉じます
- ハンドラー5が開きます
- ハンドラー5、
async_send
ask_clients
、ハンドラー6を作成 - ハンドラー5が閉じます
- ハンドラー6が導入されました(サーバーに
ask_clients
を正常に送信ask_clients
) - ハンドラー6は、ハンドラー7を作成する
async_receive
呼び出します(サーバーが既存のクライアントのリストを送信するのを待ちます) - ハンドラー6が閉じます
- ハンドラー7が呼び出され、顧客のリストを受け入れます
- ハンドラー7は
on_answer_from_serve
開始しon_answer_from_serve
(ハンドラー8が作成されます) - ハンドラー7が閉じます
- ハンドラー8が開き、クライアントのリスト(
on_clients
)がダンプに書き込まれます
慣れるまでしばらく時間がかかりますが、これを理解するとすぐに、問題を含む出力を分離し、修正が必要なコードの実際の部分を見つけることができます。
ハンドラ追跡情報をファイルに書き込む
デフォルトでは、ハンドラ追跡情報は標準エラーストリームに出力されます(
std::cerr
)。 この出力を別の場所にリダイレクトする可能性が非常に高くなります。 一方、デフォルトでは、コンソールアプリケーションの場合、エラーの出力とリセットは1か所、つまりコンソールで発生します。 ただし、Windows(非コンソール)アプリケーションの場合、エラーストリームはデフォルトで空です。
次のように、コマンドラインを使用してエラー出力をリダイレクトできます。
some_application 2>err.txt
あまりにも怠notでない場合は、次のコードフラグメントに示すように、プログラムで実行できます。
// for Windows HANDLE h = CreateFile("err.txt", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL , 0); SetStdHandle(STD_ERROR_HANDLE, h); // for Unix int err_file = open("err.txt", O_WRONLY); dup2(err_file, STDERR_FILENO);
SSL
Boost.Asioは、いくつかの基本的なSSL機能をサポートするクラスを提供します。 内部では、彼女は
OpenSSL
を使用してい
OpenSSL
。 したがって、SSLを使用する場合は、まずOpenSSLをダウンロードしてビルドします 。 原則として、特にVisual Studioなどの一般的なコンパイラがない場合、
OpenSSL
構築は簡単なタスクではないことに注意してください。
OpenSSL
コンパイルに成功した場合、Boost.Asioにはいくつかのアドオンクラスがあります。
-
ssl::stream
:ip::::socket
クラスの代わりに使用
ssl::context
:これはセッションを開始するためのコンテキストです
ssl::rfc2818_verification
:このクラスは、RFC 2818に従ってホスト名で証明書を検証する簡単な方法です
次のいくつかの記事では、いくつかの本の最初の章(3冊、おそらく4冊)の翻訳を提供したいと思います。
みなさん、ありがとうございました!