Last active
July 28, 2023 11:26
-
-
Save sehe/5ec43b7baa7fb8a15ebf to your computer and use it in GitHub Desktop.
Simplifying sequential use of Asio operations with timeouts
This file contains hidden or 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
all:TCPClient | |
CPPFLAGS+=-std=c++11 -Wall -pedantic -g -O2 -pthread | |
%.o: TCPClient.hpp | |
%: %.o | |
$(CXX) $(CPPFLAGS) $^ -o $@ -lboost_system |
This file contains hidden or 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 <iostream> | |
#include "TCPClient.hpp" | |
int main(/*int argc, char* argv[]*/) { | |
TCPClient client; | |
try { | |
client.connect("localhost", "27015"); | |
std::cout << "Response: " << client.sendMessage("Hello!") << std::endl; | |
} | |
catch (const boost::system::system_error& e) { | |
std::cerr << e.what() << std::endl; | |
} | |
catch (const std::exception& e) { | |
std::cerr << e.what() << std::endl; | |
} | |
} |
This file contains hidden or 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
#ifndef __TCPCLIENT_H__ | |
#define __TCPCLIENT_H__ | |
#include <boost/asio.hpp> | |
#include <boost/asio/high_resolution_timer.hpp> | |
#include <iostream> | |
class TCPClient { | |
public: | |
void disconnect(); | |
void connect(const std::string& address, const std::string& port); | |
std::string sendMessage(const std::string& msg); | |
private: | |
using error_code = boost::system::error_code; | |
template<typename AllowTime> void await_socket(AllowTime const& deadline_or_duration) { | |
using namespace boost::asio; | |
ioservice.reset(); | |
{ | |
high_resolution_timer tm(ioservice, deadline_or_duration); | |
tm.async_wait([this](error_code ec) { if (ec != error::operation_aborted) socket.cancel(); }); | |
ioservice.run_one(); | |
} | |
ioservice.run(); | |
} | |
struct raise { | |
template <typename... A> void operator()(error_code ec, A...) const { | |
if (ec) throw std::runtime_error(ec.message()); | |
} | |
}; | |
boost::asio::io_service ioservice { }; | |
boost::asio::ip::tcp::socket socket { ioservice }; | |
}; | |
inline void TCPClient::disconnect() { | |
using namespace boost::asio; | |
if (socket.is_open()) { | |
try { | |
socket.shutdown(ip::tcp::socket::shutdown_both); | |
socket.close(); | |
} | |
catch (const boost::system::system_error& e) { | |
// ignore | |
std::cerr << "ignored error " << e.what() << std::endl; | |
} | |
} | |
} | |
inline void TCPClient::connect(const std::string& address, const std::string& port) { | |
using namespace boost::asio; | |
async_connect(socket, ip::tcp::resolver(ioservice).resolve({address, port}), raise()); | |
await_socket(std::chrono::seconds(6)); | |
} | |
inline std::string TCPClient::sendMessage(const std::string& msg) { | |
using namespace boost::asio; | |
streambuf response; | |
async_read_until(socket, response, '\n', raise()); | |
await_socket(std::chrono::system_clock::now() + std::chrono::seconds(4)); | |
return {std::istreambuf_iterator<char>(&response), {}}; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment