I am trying to implement a kind of syslog protocol client in boost asio. I succeeded with UDP async version and I am trying to develop TCP version, but stuck. I used WinSyslog and Debian rsyslog as server and Wireshark to control data flow.
I wrote TcpConnection class and prepared test data for it. I use boost asio tcp socket and I expect that packet would be sent using connect and send handlers, but connect handler didn't called.
My Implementation:
class TcpConnection
, public boost::enable_shared_from_this<TcpConnection>
{
public:
TcpConnection(
boost::asio::io_service& io_service,
uint32_t to,
uint16_t port)
: m_socket(io_service)
, m_ep(boost::asio::ip::address_v4(to), port)
{
m_socket.open(boost::asio::ip::tcp::v4());
}
void SendMessageAsync(const boost::asio::const_buffer& message) override
{
/*
boost::system::error_code ec;
m_socket.connect(m_ep, ec);
m_socket.send(message, 0, ec);*/
m_socket.async_connect(m_ep,
boost::bind(&TcpConnection::HandleConnect, shared_from_this(), boost::asio::placeholders::error, message));
}
private:
void HandleConnect(boost::system::error_code const& ec, const boost::asio::const_buffer& message)
{
if (!ec) {
ec.message();
}
else
{
m_socket.async_send(message,
boost::bind(&TcpConnection::HandleWritten, shared_from_this(),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
}
void HandleWritten(boost::system::error_code const& ec, size_t bytes_transferred)
{
if (!ec) {
EKA_TRACE_ERROR() << TR << ec.message();
}
}
private:
boost::asio::ip::tcp::socket m_socket;
const boost::asio::ip::tcp::endpoint m_ep;
};
int main(int argc, char** argv)
{
boost::asio::io_service m_io_service;
auto connection = boost::make_shared<protocoller::syslog::TcpConnection>(
io_service, asio::ip::address::from_string("10.16.82.22"), 514);
auto messageStr = "syslog report"
connection->SendMessageAsync(boost::asio::buffer(boost::asio::buffer(messageStr.data(), messageStr.size())));
Sleep(5000);
}
I placed breakpoint in HandleConnect and this method never called. I used wireshark and there is successfull connection, but my handler didn't invoked:
I tried to find problem with BOOST_ASIO_ENABLE_HANDLER_TRACKING, but there was only @asio|1695732320.140556|0*1|socket@01580998.async_connect
And finally I tried to send by blocking socket and everything work good, so I have a problem only with async sending.
You forget to run()
the io_context
in your code.
int main()
{
boost::asio::io_service m_io_service;
auto connection = boost::make_shared<protocoller::syslog::TcpConnection>(
io_service, asio::ip::address::from_string("10.16.82.22"), 514);
auto messageStr = "syslog report"
connection->SendMessageAsync(boost::asio::buffer(boost::asio::buffer(messageStr.data(), messageStr.size())));
m_io_service.run_for(std::chrono::milliseconds(5000));
}
Here's some fixed-up version that works (some conditions were also wrong and the code wasn't self-contained):
Note that there are considerable issues with the interfaces and soon with thread-safety, unless you intend to only send one message per connection (which is does look like...?) but then the whole class should be a function.
Also consider using executors instead of service references.