chrisp
chrisp

Reputation: 629

Boost::Asio - Passing socket to second class

I am currently trying to get the following application to work:

  1. Await incoming client connection.
  2. Start async. timer in another class.
  3. While the timer runs repeatedly, do other stuff such as async_read and async_write.

Current source code:

#define BOOST_ASIO_ENABLE_HANDLER_TRACKING

#include <WinSock2.h>
#include <Mswsock.h>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include "TimerClass.hpp"

using namespace boost::asio;
using namespace boost::asio::ip;

TimerClass *timerClass;

void acceptHandler(const boost::system::error_code &errorCode, tcp::socket *socket) {
    timerClass = new TimerClass(socket);
    timerClass->startTimer();
    while(true) {
        // Do other suff such as async_write, ...
    }
}

int main(int argc, char** argv) {
    io_service ioService;
    tcp::socket socket(ioService);
    tcp::acceptor acceptor{ ioService, tcp::endpoint{ tcp::v4(), 12345 } };
    acceptor.listen();
    acceptor.async_accept(socket, boost::bind(acceptHandler, _1, &socket));
    ioService.run();
    return EXIT_SUCCESS;
}

TimerClass.hpp:

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

using namespace boost::asio;
using namespace boost::posix_time;

class TimerClass {
public:
    TimerClass(ip::tcp::socket *socket);
    void startTimer();
    void timerHandler(const boost::system::error_code& errorCode);
    deadline_timer timer;
};

TimerClass.cpp:

#include <boost/bind.hpp>
#include "TimerClass.hpp"

TimerClass::TimerClass(ip::tcp::socket *socket) : timer(socket->get_io_service(), boost::posix_time::seconds(1)) {}

void TimerClass::startTimer() {
    timer.async_wait(boost::bind(&TimerClass::timerHandler, this, boost::asio::placeholders::error));
}

void TimerClass::timerHandler(const boost::system::error_code& errorCode) {
    timer.expires_at(timer.expires_at() + boost::posix_time::seconds(1));
    timer.async_wait(boost::bind(&TimerClass::timerHandler, this, boost::asio::placeholders::error));
}

Handler Tracking Output:

@asio|1461070492.111630|0*1|[email protected]_accept
@asio|1461070498.527997|>1|ec=system:0

Questions:

  1. Why won't it even call async_wait in startTimer? Debugging shows that startTimer gets called but I can't find anything in the Handler Tracking output. Why is that?
  2. Am I correctly passing the socket to the TimerClass?
  3. Without the infinite while(true) loop in the acceptHandler the acceptHandler returns but the application crashes before the io_service properly returns. How is that?

Upvotes: 0

Views: 842

Answers (1)

Nacho
Nacho

Reputation: 1124

I compiled your code and it works for me (using boost version 1.54).

With your code I get the following output:

@asio|1461081908.437388|0*1|[email protected]_accept 
@asio|1461081983.220840|>1|ec=system:0    
@asio|1461081983.221817|1*2|[email protected]_wait

To make it run properly I had to remove the while(true) on your acceptHandler, obtaining the following output (added a std::cout inside the handler):

@asio|1461083707.104424|0*1|[email protected]_accept
@asio|1461083709.061824|>1|ec=system:0
@asio|1461083709.062803|1*2|[email protected]_wait
@asio|1461083709.062803|<28158494073611763|
@asio|1461083710.064992|>2|ec=system:0
@asio|1461083710.064992|2|[email protected]
@asio|1461083710.064992|2*3|[email protected]_wait
TimerHandler executed...
@asio|1461083710.065971|<28169626628843099|
@asio|1461083711.065223|>3|ec=system:0
@asio|1461083711.065223|3|[email protected]
@asio|1461083711.065223|3*4|[email protected]_wait
TimerHandler executed...

I actually did this test using only the header TimerClass.hpp (defining the methods directly within it -I was lazy-) and it worked like a charm, the problem seems to be when using the .cpp file, that's why I asked if you were using include guards (not the issue though, already tested).


You should consider changing your design approach though, i.e. do not use blocking loops in you handlers, just call another asynchronous operation if needed (like async_read or async_write).

Take a look at this question and corresponding accepted answer for a nice server implementation idea. Or try to adapt some of the boost examples to your needs.

As per the segmentation fault you get when separating declaration from definition in the corresponding header and implementation files, you might want to check this other question.

Upvotes: 2

Related Questions