
毛利です。
THTTPClientを使って非同期HTTPリクエストを試してみました。
TNetHTTPClientと言うコンポーネントもありますが、TNetHTTPClient classにはTHTTPClientが 内包されています。
THTTPClientの非同期HTTPが使えるメソッドは下記です。
メソッド名 | 機能 | |
BeginDelete | public | 非同期 HTTP リクエストを、DELETE HTTP リクエスト メソッドを使用して開始します。 |
BeginExecute | public | 非同期 HTTP リクエストを開始します。 |
BeginGet | public | 非同期 HTTP リクエストを、GET HTTP リクエスト メソッドを使用して開始します。 |
BeginGetRange | public | 非同期 HTTP リクエストを、GET HTTP リクエスト メソッドを Range ヘッダーと共に使用して開始します。 |
BeginHead | public | 非同期 HTTP リクエストを、HEAD HTTP リクエスト メソッドを使用して開始します。 |
BeginMerge | public | 非同期 HTTP リクエストを、MERGE HTTP リクエスト メソッドを使用して開始します。 |
BeginMergeAlternative | public | MERGE HTTP リクエスト メソッドを使用した非同期 HTTP リクエストを、PUT HTTP リクエスト メソッドとしてマス |
BeginOptions | public | 非同期 HTTP リクエストを、OPTIONS HTTP リクエスト メソッドを使用して開始します。 |
BeginPatch | public | 非同期 HTTP リクエストを、PATCH HTTP リクエスト メソッドを使用して開始します。 |
BeginPatchAlternative | public | PATCH HTTP リクエスト メソッドを使用した非同期 HTTP リクエストを、PUT HTTP リクエスト メソッドとしてマスクします |
BeginPost | public | 非同期 HTTP リクエストを、POST HTTP リクエスト メソッドを使用して開始します。 |
BeginPut | public | 非同期 HTTP リクエストを、PUT HTTP リクエスト メソッドを使用して開始します。 |
BeginTrace | public | 非同期 HTTP リクエストを、TRACE HTTP リクエスト メソッドを使用して開始します。 |
コンソール アプリケーションを新規プロジェクトC++Builder(Win64)で作成しTHTTPClientのBeginGet()を試したコードです。
//// struct _net_request:public TObject { using inherited = TObject; std::mutex m_; bool f_wait{false}; THTTPClient* f_netc_{THTTPClient::Create()}; String f_temp; _net_request():inherited() { f_netc_->OnReceiveData = receive_event; } void __fastcall receive_event(TObject * const Sender, __int64 AContentLength, __int64 AReadCount, bool &Abort) { if (Abort == false) { std::wcout << L"AReadCount=" << AReadCount << std::endl; } } void set_wait(const bool value_) { std::lock_guard<std::mutex> lk_(m_); f_wait = value_; } bool get_wait() { std::lock_guard<std::mutex> lk_(m_); return f_wait; } __fastcall ~_net_request(void) { delete f_netc_; } }; int _tmain(int argc, _TCHAR* argv[]) { String url_ = argv[1]; String fname_ = argv[2]; String path_name_ = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetSharedDownloadsPath(), fname_); std::unique_ptr<_net_request> req_ = std::make_unique<_net_request>(); // int lengs_ = req_->f_netc_->Head(url_)->ContentLength; std::cout << "ContentLength" << lengs_ << std::endl; std::unique_ptr<TFileStream> down_file_ = std::make_unique<TFileStream>(path_name_, fmCreate); down_file_->Position = 0; TDateTime tstart_ = Now(); _di_IAsyncResult res_= req_->f_netc_->BeginGet([&req_, &tstart_](const System::Types::_di_IAsyncResult AsyncResult) { req_->set_wait(true); TDateTime tend_ = Now() - tstart_; std::wcout << FormatDateTime("hh:nn:ss.zzz",tend_).w_str() << L" End Download." << std::endl; }, url_, down_file_.get()); if (res_ != nullptr) { // Wait until BeginGet() is over. while (! req_->get_wait() ) { std::this_thread::sleep_for(std::chrono::seconds(2)); } } return 0; }
コマンドラインで URLとファイル名を指定すればダウンロードを非同期で実行します。
ダウンロード中のステータスはコールバックで処理します。
THTTPClient::OnReceiveDataです。
//// f_netc_->OnReceiveData = receive_event;
BeginGet()関数_di_TAsyncCallbackはLambdaを使って処理が可能です。
//// _di_IAsyncResult res_= req_->f_netc_->BeginGet([&req_, &tstart_](const System::Types::_di_IAsyncResult AsyncResult) { req_->set_wait(true); TDateTime tend_ = Now() - tstart_; std::wcout << FormatDateTime("hh:nn:ss.zzz",tend_).w_str() << L" End Download." << std::endl; }, url_, down_file_.get());
最後にコンソールアプリなので終了を待っています。
//// // Wait until BeginGet() is over. while (! req_->get_wait() ) { std::this_thread::sleep_for(std::chrono::seconds(2)); }
メインでf_wait(bool)を待っています、裏のスレッドで終了時にf_waitを書くのでstd::mutexを使ってロックしています。
細川さんがDelphi版で詳しく説明されています
https://github.com/mojeld/THTTPClient_Console