インターネットソケットとUNIXドメインソケットの両方からのメッセージをリッスンして処理するアプリケーションがあります。ここで、インターネットソケットにSSLを追加する必要があります。アプリケーションのすべてのソケットに、単一のio_service
オブジェクトを使用していました。io_service
ネットワークソケットとUNIXドメインソケットに別々のオブジェクトを追加する必要があるようです。アプリケーションにスレッドがなく、データと接続を処理するためasync_send
にandasync_recieve
を使用しています。非同期ハンドラーでasync_accept
複数のオブジェクトを使用する例を教えてください。io_service
2 に答える
質問には、複数のio_service
オブジェクトが必要であるかのように、ある程度の不確実性があります。リファレンスドキュメント、または個別のオブジェクトを義務付けるSSLおよびUNIXドメインソケットの概要には何も見つかりませんでした。io_service
とにかく、ここにいくつかのオプションがあります:
シングルio_service
:
単一のを使用してみてくださいio_service
。
オブジェクトへの直接ハンドルがなくてもio_service
、ソケットなどのBoost.Asio I / Oオブジェクトへのハンドルがある場合は、をio_service
呼び出すことで、関連付けられたオブジェクトへのハンドルを取得できますsocket.get_io_service()
。
ごとにスレッドを使用しますio_service
:
複数のio_service
オブジェクトが必要な場合は、それぞれにスレッドを割り当てio_service
ます。このアプローチは、Boost.AsioのHTTPサーバー2の例で使用されています。
boost::asio::io_service service1;
boost::asio::io_service service2;
boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &service1));
service2.run();
threads.join_all();
このアプローチの結果の1つは、アプリケーションによるスレッドセーフの保証が必要になる場合があることです。たとえば、service1
とservice2
の両方にを呼び出す完了ハンドラーがあるmessage_processor.process()
場合message_processor.process()
は、スレッドセーフであるか、スレッドセーフな方法で呼び出される必要があります。
投票io_service
:
io_service
に非ブロッキングの代替手段を提供しrun()
ます。すべて io_service::run()
の作業が完了するまでブロックしio_service::poll()
ますが、実行の準備ができてブロックしないハンドラーを実行します。これにより、単一のスレッドが複数のio_service
オブジェクトに対してイベントループを実行できるようになります。
while (!service1.stopped() &&
!service2.stopped())
{
std::size_t ran = 0;
ran += service1.poll();
ran += service2.poll();
// If no handlers ran, then sleep.
if (0 == ran)
{
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
}
すぐに実行できるハンドラーがないときにタイトビジーループを防ぐために、スリープ状態で追加する価値がある場合があります。このスリープにより、イベントの全体的な処理に遅延が生じる可能性があることに注意してください。
ハンドラーを単一に転送しますio_service
:
興味深いアプローチの1つは、を使用しstrand
て完了ハンドラーを単一のに転送することio_service
です。これにより、スレッドごとが可能になりますがio_service
、すべての完了ハンドラーが単一のサービスを介して投稿するため、アプリケーションにスレッドセーフの保証を行わせる必要がなくなります。このサービスのイベントループは単一のスレッドによってのみ処理されます。
boost::asio::io_service service1;
boost::asio::io_service service2;
// strand2 will be used by service2 to post handlers to service1.
boost::asio::strand strand2(service1);
boost::asio::io_service::work work2(service2);
socket.async_read_some(buffer, strand2.wrap(read_some_handler));
boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &service1));
service2.run();
threads.join_all();
このアプローチにはいくつかの結果があります。
- mainによって実行されることを意図したハンドラーは、
io_service
を介してラップされる必要がありますstrand::wrap()
。 - 非同期チェーンは2つを実行するよう
io_service
になり、さらに複雑になりました。io_service
セカンダリが機能しなくなり、セカンダリrun()
が復帰した場合を考慮することが重要です。
非同期チェーンが同じ内で発生するのは一般的ですio_service
。したがって、完了ハンドラーがに追加の作業を投稿するため、サービスの作業が不足することはありませんio_service
。
| .------------------------------------------.
V V |
read_some_handler() |
{ |
socket.async_read_some(..., read_some_handler) --'
}
一方、ストランドを使用して作業を別のに転送するio_service
と、ラップされたハンドラーが内で呼び出されservice2
、完了ハンドラーがにポストされservice1
ます。ラップされたハンドラーがで唯一の作業であった場合、作業がなくなり、service2
戻ります。service2
servce2.run()
service1 service2
====================================================
.----------------- wrapped(read_some_handler)
| .
V .
read_some_handler NO WORK
| .
| .
'----------------> wrapped(read_some_handler)
これを説明するために、サンプルコードはio_service::work
forを使用して、明示的にに指示されるまでブロックされservice2
たままになります。run()
stop()
クライアントではなくサーバーを作成しているようです。これが役立つかどうかはわかりませんが、ASIOを使用してクライアントから6台のサーバーと通信しています。TCP / IP SSL/TSLを使用します。ここにコードへのリンクがあります
複数のソケットオブジェクトで1つのio_serviceオブジェクトのみを使用できるはずです。ただし、本当に複数のio_serviceオブジェクトが必要であると判断した場合は、そうするのはかなり簡単です。私のクラスでは、io_serviceオブジェクトは静的です。したがって、io_serviceオブジェクトのインスタンスを1つだけ作成するコンストラクターのロジックとともに、staticキーワードを削除するだけです。サーバーに予想される接続数によっては、新しいソケット接続ごとにスレッドを作成するよりも、ソケットI/Oの処理専用のスレッドプールを使用する方がよいでしょう。