1

Boost ASIO の読み取りまたは書き込み操作に一定の時間がかかる場合にキャンセルする方法を探していました。私のサーバーは HTTP リクエストを送信し、それらのリクエストから結果を読み取っています。そのため、もともとは同期読み取り/書き込みとしてコーディングしていました。時間がかかる場合は、処理を続行して、返された結果を無視していました。これにより、サーバーがダウンした場合に問題が発生し、サーバーが多くのソケットに対して開かれ、クラッシュしました。そのため、遅延が長すぎる場合は読み取り/書き込みをキャンセルすることにしましたが、実行中のスレッドを破棄せずに同期読み取り/書き込みをキャンセルできないようです。これはやりたくありません。そこで、非同期呼び出しで同期読み取り/書き込みを模倣し、タイムアウト時に呼び出しをキャンセルする方法に関する投稿を見つけました。 これ 私がフォローした投稿です。この投稿はかなり古いことを知っているので、そのバージョンと私が使用しているバージョン (1.48) 以降に関数呼び出しが変更されたかどうかはわかりませんが、これは正しく機能していないようです。これが私のコードです

bool connection::query_rtb(const std::string &request_information, std::string &reply_information)
{
    try
    {
        boost::optional<boost::system::error_code> timer1_result, timer2_result, write_result, read_result;
        boost::array<char,8192> buf;
        buf.assign(0);

        boost::asio::deadline_timer dt(io_service_);
        dt.expires_from_now(boost::posix_time::milliseconds(100));
        dt.async_wait(boost::bind(&connection::set_result, this, &timer1_result, _1, "timer1"));
        boost::asio::async_write(socket_, boost::asio::buffer(request_information, request_information.size()), boost::bind(&connection::set_result, this, &write_result, _1, "write"));
        io_service_.reset();

        while(io_service_.run_one())
        {
            if(write_result)
            {
                dt.cancel();
            }
            else if(timer1_result)
            {
                socket_.cancel();
            }
        }


        boost::asio::deadline_timer dt2(io_service_);
        dt2.expires_from_now(boost::posix_time::milliseconds(3000));
        dt2.async_wait(boost::bind(&connection::set_result, this, &timer2_result, _1, "timer2"));
        boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
        //socket_.async_receive(boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));

        io_service_.reset();
        while(io_service_.run_one())
        {
            if(read_result)
            {
                dt2.cancel();
            }
            if(timer2_result)
            {
                socket_.cancel();
            }
        }


        reply_information = buf.data();
        std::cout << reply_information << std::endl;
        return true;
    }catch(std::exception& e)
    {
         std::cerr << e.what() << std::endl;
    }
}

void persistent_connection::set_result(boost::optional<boost::system::error_code> *a, boost::system::error_code ec, std::string t)
{
    std::cout << t << std::endl;
    a->reset(ec);
}

誰かがこのコードに何か問題があるのか​​ 、またはなぜそれが機能しないのかについて何か考えがあるのだろうかと思っていました. 現在、書き込みは問題ないようですが、タイマーで dt2 が完了するまで読み取りは行われません。さらに情報が必要な場合はお知らせください。喜んで提供させていただきます。

編集:

以前にテストしたと思っていたものをテストして、うまくいったようです。async_receive代わりに使用すると、async_read私が抱えていた問題が解決したようです。なぜこれが私の問題を引き起こすのでしょうか? 私の論理に問題があるのか​​、それともasync_read通常はそのように行動するのかを知りたい.

4

1 に答える 1

1
boost::array<char,8192> buf;

...

boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));

ソケットから 8192 バイトを読み取るようにプログラムに指示しました。async_read()フリー関数を使用するロジックをasync_receive()メンバー関数に切り替えることでこの問題が解決する場合は、ドキュメントを参照してください。

備考

受信操作では、要求されたバイト数のすべてを受信できない場合があります。async_read非同期操作が完了する前に、要求された量のデータを確実に受信する必要がある場合は、関数の使用を検討してください。

于 2013-05-02T14:45:39.887 に答える