Boost Asio and asynchronous I/O
I'm just going to check if anyone has any experience with Boost Asio here...
I can't get asynchronous I/O to work properly...
This code may be a little long, but it is simple:
Code:
#include <memory>
#include <algorithm>
#include <windows.h>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/cstdint.hpp>
#include <boost/scope_exit.hpp>
#include <boost/bind.hpp>
using namespace boost;
using asio::ip::tcp;
namespace ip = asio::ip;
class tcp_connection
{
protected:
std::shared_ptr<tcp::socket> m_socket;
public:
tcp_connection(asio::io_service& io_service): m_socket(new tcp::socket(io_service)) {}
tcp::socket& get_socket() { return *m_socket; }
};
void handle_request(tcp_connection& connection, const boost::system::error_code& err);
int APIENTRY _tWinMain(HINSTANCE /*hInstance*/,
HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/,
int /*nCmdShow*/)
{
asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 1));
for (;;)
{
tcp_connection connection(io_service);
boost::system::error_code err;
acceptor.accept(connection.get_socket(), err);
boost::thread thread(&handle_request, connection, err);
}
}
std::vector<tcp::endpoint> g_SmsGenerators;
const char MsgSmsNotAvailable = 1;
const char MsgReplyOk = 5; // Data was recieved; OK to send more now
class XSocket
{
public:
XSocket(tcp::socket& socket): m_socket(socket)
{
m_Event = CreateEvent(nullptr, FALSE, FALSE, L"");
}
template<typename T> void send(const T& data, boost::uint32_t Timeout)
{
const T _data[1] = { data };
//m_socket.get_io_service().run();
asio::async_write(m_socket, asio::buffer(_data), boost::bind(&XSocket::handle_send_complete, this, _1, _2));
m_socket.get_io_service().run();
unsigned long status = WaitForSingleObject(m_Event, Timeout * 1000);
m_socket.cancel();
}
private:
void handle_send_complete(const boost::system::system_error& err, std::size_t bytes)
{
SetEvent(m_Event);
}
public:
template<typename T> T get()
{
std::vector<char> buf(1024);
m_socket.receive(asio::buffer(buf));
char reply[1] = { MsgReplyOk };
m_socket.send(asio::buffer(reply));
return boost::lexical_cast<T>(&buf[0]);
}
protected:
tcp::socket& m_socket;
HANDLE m_Event;
};
void handle_request(tcp_connection& connection, const boost::system::error_code& err)
{
XSocket socket(connection.get_socket());
auto data = socket.get<int>();
switch (data)
{
case MsgRequestSms:
socket.send(MsgSmsNotAvailable, 10);
}
}
The problem is basically that at the SECOND client connection, the send complete handler is never run (handle_send_complete). Instead, the wait times out. See XSocket::send.
What is worse, on the THIRD client connection, it sees that the handler for the second write is complete and calls handle_send_complete. However, by then, the associated instance of XSocket is long gone, and it crashes horribly.
What I don't understand is how to make sure that bloody library calls handle_send_complete EVERY time the send finishes. It's obviously important.
Any insight whatsoever would be appreciated.