I'm currently working a small servlet to send simulation data over TCP, using boost::asio for the networking part. I've managed to get comms between two processes on my machine (the simple client is written in Python). The problem lies in that the same data keeps being sent over the socket, instead of being updated.
I'm using two threads: one which runs a simulation, creating data, and updates the server's connection object with the current data. The second runs the server, and every so often writes the current data to the socket. I've created a minimal example to share with you here (it compiles with MSVC++ 12.0, and has the problem I'm talking about if you care to replicate).
tcp_server * server;
bool connected = false;
void runServer() {
try
{
boost::asio::io_service io_service;
server = new tcp_server(io_service);
connected = true;
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
void runSim() {
for (int i = 0; i < 1000; i++) {
if (connected)
server->setData("Current Message: " + std::to_string(i));
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
}
int _tmain(int argc, _TCHAR* argv[])
{
boost::thread serverThread(runServer);
boost::thread simThread(runSim);
simThread.join();
serverThread.join();
return 0;
}
Here are the two classes, TCP_Connection and TCP_Server. These pretty closely replicate those found in the boost::asio tutorials on the boost website right now.
class tcp_connection
: public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
message_ = make_daytime_string();
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this()));
}
void setData(std::string msg) {
boost::unique_lock<boost::shared_mutex> msgLock(msgMutex, boost::try_to_lock);
if (msgLock.owns_lock()) {
message_ = msg;
}
}
private:
tcp_connection(boost::asio::io_service& io_service)
: socket_(io_service)
{
timer_ = new boost::asio::deadline_timer(io_service,boost::posix_time::milliseconds(250));
}
void handle_write()
{
boost::shared_lock<boost::shared_mutex> msgLock(msgMutex);
std::cout << "Writing to socket: " << message_ << std::endl;
boost::asio::write(socket_, boost::asio::buffer(message_));
timer_->expires_at(timer_->expires_at() + boost::posix_time::milliseconds(1500));
timer_->async_wait(boost::bind(&tcp_connection::handle_write, shared_from_this()));
}
tcp::socket socket_;
std::string message_;
int counter_;
boost::asio::deadline_timer * timer_;
boost::shared_mutex msgMutex;
};
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
{
start_accept();
}
void setData(std::string msg) {
if (current_connection != NULL) {
current_connection->setData(msg);
}
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
current_connection = new_connection;
}
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
std::cout << "New Connection on 127.0.0.1" << std::endl;
}
start_accept();
}
tcp::acceptor acceptor_;
tcp_connection::pointer current_connection;
};
Through judicious use of std::cout, I've managed to determine that the server thread is getting the data from the simulation thread, and the connection object is being passed it as well (because the setData() method is being called when it is supposed to). For whatever reason, it looks like the connection's member 'message_' is not being updated. I know also that the connection is not being reset or recreated from the "New Connection" update to the console.