[英]How to fix Boost::Asio Client Http request error?
我正在嘗試通過觀看此視頻來精簡 C++ 的Boost ::Asio 網絡庫,但我堅持使用異步線程發出請求。
編碼:
#include "stdafx.h"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ts/buffer.hpp>
#include <boost/asio/ts/internet.hpp>
#include <boost/system/error_code.hpp>
std::vector<char> vBuffrer(20 * 1024);
void GrabSomeData(boost::asio::ip::tcp::socket& socket) {
socket.async_read_some(boost::asio::buffer(vBuffrer.data(), vBuffrer.size()),
[&](std::error_code ec, std::size_t length)
//boost::system::error_code ec
{
if (!ec)
{
std::cout << "\n\nRead" << length << "bytes\n\n";
for (int i = 0; i < length; i++)
std::cout << vBuffrer[i];
GrabSomeData(socket);
}
});
}
int main()
{
boost::system::error_code ec;
boost::asio::io_context context;
boost::asio::io_context::work idleWork(context);
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::make_address("13.107.21.200",ec),80);
boost::asio::ip::tcp::socket socket(context);
std::thread thrContext = std::thread([&]() {context.run(); });
std::cout << "Starting " << std::endl;
socket.connect(endpoint,ec);
if (!ec)
{
std::cout << "Connected ! " << std::endl;
}
else {
std::cout << "Fail to connect ! " << ec.message() << std::endl;
}
if (socket.is_open()) {
GrabSomeData(socket);
std::string sRequest =
"GET /index.html HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection: close\r\n\r\n";
socket.write_some(boost::asio::buffer(sRequest.data(), sRequest.size()), ec);
using namespace std::chrono_literals;
std::this_thread::sleep_for(2800ms);
//std::this_thread::sleep_for(1ms);
context.stop();
if (thrContext.joinable()) thrContext.join();
}
system("pause");
return 0;
}
Microsoft Visual Studio 給我這個:
Error C2752 'asio_prefer_fn::call_traits<boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context &>,boost::asio::execution::detail::blocking::never_t<0>,boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0>>> &,void (const boost::asio::execution::detail::blocking::possibly_t<0> &,boost::asio::execution::allocator_t<std::allocator<void>>),void>': more than one partial specialization matches the template argument list boostasiotest c:\boost\boost_1_75_0\boost\asio\detail\handler_work.hpp 353
Error C2893 Failed to specialize function template 'enable_if<asio_prefer_fn::call_traits<T,void(P0,P1,PN...),void>::overload==,call_traits<T,void(P0,P1,PN...),void>::result_type>::type asio_prefer_fn::impl::operator ()(T &&,P0 &&,P1 &&,PN &&...) noexcept(<expr>) const' boostasiotest c:\boost\boost_1_75_0\boost\asio\detail\handler_work.hpp 353
在我添加GrabSomeData function 之前一切正常,我完全不知道如何修復它,任何幫助將不勝感激。
PS: Boost網站上有一個關於這個主題的例子,但它是面向object的,所有的指針都指向class,我(認為)它無濟於事。
像評論者一樣,我無法復制您的信息:它只是編譯,
現在,我確實看到了其他問題:
write_some
可能不會寫入所有數據 - 您需要確保組合寫入操作
競爭條件:由於您在線程上執行GrabSomeData
,因此您需要同步對tcp::socket
和buffer
(共享資源)的訪問。
io_context
本身是線程安全的。
在這種情況下,很容易避免,因為在發送請求之前不需要啟動異步操作:
write(socket, boost::asio::buffer(sRequest)); GrabSomeData(socket);
async_read_some
與寫入端有類似的問題。 您將需要一個組合讀取操作來讀取預期的 output so read_until(socket, buf, "\r\n\r\n")
然后根據Content-Length
header、 Connection: Close
等讀取預期的內容量(想想分塊編碼)。
您目前沒有存儲和訪問響應的好方法。 使用streambuf(單個組合讀取)會容易得多。
如果您想真正可靠,請使用 Beast 接收 HTTP/1.1 響應(甚至可以分塊),而不必擔心它何時完成(庫會為您完成):
auto GrabSomeData(tcp::socket& socket) { http::response<http::string_body> res; auto buf = boost::asio::dynamic_buffer(vBuffer); http::read(socket, buf, res); return res; }
哦,不要在線程上這樣做(為什么會這樣?它實際上只是引入了未定義的行為而沒有任何收獲):
#include <boost/asio.hpp>
#include <boost/beast/http.hpp>
#include <iostream>
#include <iomanip>
using boost::asio::ip::tcp;
std::vector<char> vBuffer; // TODO FIXME global variable
auto GrabSomeData(tcp::socket& socket) {
namespace http = boost::beast::http;
http::response<http::string_body> res;
auto buf = boost::asio::dynamic_buffer(vBuffer);
http::read(socket, buf, res);
return res;
}
int main() try {
boost::asio::io_context context;
std::cout << "Starting " << std::endl;
tcp::endpoint endpoint(boost::asio::ip::make_address("13.107.21.200"), 80);
tcp::socket socket(context);
socket.connect(endpoint);
std::cout << "Connected" << std::endl;
std::string const sRequest = "GET /index.html HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection: close\r\n"
"\r\n";
write(socket, boost::asio::buffer(sRequest));
auto response = GrabSomeData(socket);
std::cout << "Response body length: " << response.body().size() << std::endl;
std::cout << "Response headers: " << response.base() << std::endl;
std::cout << "Response body: " << std::quoted(response.body()) << std::endl;
context.run(); // run_for(10s) e.g.
} catch (boost::system::system_error const& se) {
std::cerr << "Error: " << se.code().message() << std::endl;
}
此示例打印:
Starting
Connected
Response body length: 194
Response headers: HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
X-MSEdge-Ref: 0BstXYAAAAACeQ2y+botzQISiBe2U3iGCQ0hHRURHRTE0MDgARWRnZQ==
Date: Sun, 21 Mar 2021 22:39:02 GMT
Connection: close
Response body: "<h2>Our services aren't available right now</h2><p>We're working to restore all services as soon as possible. Please check back soon.</p>0BstXYAAAAACeQ2y+botzQISiBe2U3iGCQ0hHRURHRTE0MDgARWRnZQ=="
注意它確實使用了分塊編碼,您似乎沒有預料到。
感謝@sehe 的回答和建議,花了很長時間,但我已經升級到 New Windows10和Visual Studio 2019和Boost 1_76並且問題解決了!
這些錯誤與代碼完全無關!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.