Created
November 4, 2023 08:24
-
-
Save rohith2506/fc90430b377586f4ab8fb9b103229763 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <thread> | |
#include <iostream> | |
#include <coroutine> | |
#include <optional> | |
#include <variant> | |
#include <vector> | |
#include <utility> | |
#include <string> | |
#include <chrono> | |
#include <boost/asio.hpp> | |
#include <boost/asio/ssl.hpp> | |
#include <boost/json.hpp> | |
#include <boost/beast.hpp> | |
#include <boost/asio/io_context.hpp> | |
#include <boost/asio/ssl/context.hpp> | |
#include <boost/asio/ip/tcp.hpp> | |
#include <boost/asio/spawn.hpp> | |
#include <boost/coroutine/all.hpp> | |
#include <boost/beast/ssl/ssl_stream.hpp> | |
#include <boost/beast/core/tcp_stream.hpp> | |
#include <boost/beast/core/flat_static_buffer.hpp> | |
#include <boost/beast/http.hpp> | |
#include <boost/beast/http/string_body.hpp> | |
#include <boost/beast/http/verb.hpp> | |
#include <boost/asio/awaitable.hpp> | |
#include <boost/asio/detached.hpp> | |
class http_client { | |
private: | |
using response = boost::beast::http::response<boost::beast::http::string_body>; | |
std::string http_hostname; | |
std::string ip_address; | |
boost::asio::ssl::context ssl_context; | |
boost::asio::ip::tcp::resolver hostname_resolver; | |
std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream>> tcp_stream; | |
boost::beast::flat_static_buffer<4 * 1024 * 1024> receive_flat_buffer; | |
public: | |
http_client(const std::string& http_name, boost::asio::io_context& io_context) : | |
http_hostname(http_name), | |
ssl_context(boost::asio::ssl::context::tlsv12_client), | |
hostname_resolver(io_context), | |
tcp_stream(boost::beast::ssl_stream<boost::beast::tcp_stream>(io_context, ssl_context)), | |
receive_flat_buffer() | |
{ | |
ssl_context.set_verify_mode(boost::asio::ssl::verify_peer); | |
ssl_context.set_options( | |
boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | | |
boost::asio::ssl::context::no_sslv3 | boost::asio::ssl::context::single_dh_use); | |
if (!SSL_set_tlsext_host_name(tcp_stream->native_handle(), http_hostname.c_str())) { | |
boost::beast::error_code error_code{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()}; | |
throw boost::beast::system_error{error_code}; | |
} | |
auto const resolved_endpoint = hostname_resolver.resolve(http_hostname, "443"); | |
ip_address = resolved_endpoint->endpoint().address().to_string(); | |
boost::beast::get_lowest_layer(tcp_stream.value()).connect(resolved_endpoint); | |
boost::beast::get_lowest_layer(tcp_stream.value()).socket().set_option(boost::asio::socket_base::keep_alive(true)); | |
boost::beast::get_lowest_layer(tcp_stream.value()).socket().set_option(boost::asio::ip::tcp::no_delay(true)); | |
std::cout << "Connected to REST endpoint at IP address <" << ip_address << "> which was resolved from <" << resolved_endpoint->host_name() << std::endl; | |
tcp_stream->handshake(boost::asio::ssl::stream_base::client); | |
} | |
void send_request(boost::asio::io_context& io_context, const std::string& target, const std::function<void(response)>& callback) { | |
boost::asio::spawn( | |
io_context, [target = std::move(target), callback = std::move(callback), this](boost::asio::yield_context yield_context) mutable | |
{ | |
boost::beast::http::request<boost::beast::http::string_body> http_request{ | |
boost::beast::http::verb::get, | |
target, | |
11}; | |
http_request.set(boost::beast::http::field::host, http_hostname); | |
http_request.set(boost::beast::http::field::content_type, "application/json"); | |
http_request.set(boost::beast::http::field::connection, "Keep-Alive"); | |
http_request.set(boost::beast::http::field::keep_alive, "timeout=86400"); | |
http_request.keep_alive(true); | |
http_request.prepare_payload(); | |
size_t bytes_transferred = boost::beast::http::async_write(tcp_stream.value(), http_request, yield_context); | |
response http_response; | |
boost::beast::http::async_read(tcp_stream.value(), receive_flat_buffer, http_response, yield_context); | |
callback(http_response); | |
} | |
); | |
} | |
}; | |
int main() { | |
boost::asio::io_context io_context{}; | |
std::string host_name{"fapi.binance.com"}; | |
http_client client(host_name, io_context); | |
for (int i = 0; i < 100; i++) { | |
auto const stime = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); | |
client.send_request(io_context, "/fapi/v1/time", [&](boost::beast::http::response<boost::beast::http::string_body> const& http_response) {}); | |
auto const etime = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); | |
std::cout << "time diff = " << etime - stime << std::endl; | |
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | |
} | |
io_context.run(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
compiler flags:
g++ -std=c++20 -O2 -flto -g http_client.cpp -I/home/dev/vcpkg/installed/x64-linux/include -L/home/dev/vcpkg/installed/x64-linux/lib -lboost_system -lboost_coroutine -lboost_thread -lboost_json -lssl -lcrypto -lboost_context