Discussion:
[asio-users] asio: handler not being called after call to io_service.run()
Daniel Tracy
2012-06-08 21:32:20 UTC
Permalink
I'm new to boost::asio, and I put together a small program to test my
understanding of it. I have an asynchronously communicating client and
server written below. I've narrowed down the problem to the following: On
the client, if I initiate an async_write in the handler for async_connect,
it works fine (the handler given to async_write gets called). If, however,
I let it fall out of the io_service.run() call and later perform the
async_write, the next call to io_service.run() just falls through.

Below is the code for the server (I've excluded error handling, etc).

#include <boost/asio.hpp>
#include <string>
#include <boost/bind.hpp>

class NetServer {
boost::asio::io_service io_service;
boost::asio::ip::tcp::endpoint endpoint;
boost::asio::ip::tcp::acceptor acceptor;
boost::asio::ip::tcp::socket sock;
boost::array<uint64_t, 1> read_buffer;
std::vector<char> write_buffer;

void write_handler(const boost::system::error_code &ec, std::size_t
bytes_transferred)
{
boost::asio::async_read(sock, boost::asio::buffer(read_buffer),
boost::bind(&NetServer::read_request_handler, boost::ref(*this), _1, _2));
// read next request...
}

void read_request_handler(const boost::system::error_code& ec, std::size_t
bytes_transferred)
{
assert( bytes_transferred == sizeof(uint64_t) );
uint64_t newSize = read_buffer[0];
uint64_t oldSize = write_buffer.size();
if( newSize > oldSize )
{
write_buffer.resize(newSize);
for( uint64_t i = oldSize; i < newSize; ++i )
write_buffer[i] = (char) (i % 128);
}
boost::asio::async_write(sock, boost::asio::buffer(&write_buffer[0],
newSize), boost::bind(&NetServer::write_handler, boost::ref(*this), _1,
_2));
}

void accept_connection_handler(const boost::system::error_code& ec)
{
boost::asio::async_read(sock, boost::asio::buffer(read_buffer),
boost::bind(&NetServer::read_request_handler, boost::ref(*this), _1, _2));
}

public:
NetServer() : endpoint(boost::asio::ip::tcp::v4(), 8000),
acceptor(io_service, endpoint), sock(io_service) {}
void run() {
acceptor.listen();
acceptor.async_accept(sock,
boost::bind(&NetServer::accept_connection_handler, boost::ref(*this), _1));
io_service.run();
}
};

int main(int argc, const char * argv[])
{
NetServer nserve;
nserve.run();
}

And now the code for the client:

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
#include <vector>

class NetClient_async {
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver;
boost::asio::ip::tcp::socket sock;
boost::array<char, 131072> read_buffer;
boost::array<uint64_t, 1> read_size_param;
uint64_t bytes_to_read;
uint64_t bytes_read_so_far;

void read_handler(const boost::system::error_code& ec, size_t bytes_read) {
for( uint64_t i = 0; i < bytes_read; ++i )
assert(read_buffer[i] == char((bytes_read_so_far+i) % 128));
bytes_read_so_far += bytes_read;
if( bytes_read_so_far < bytes_to_read )
sock.async_read_some(boost::asio::buffer(read_buffer),
boost::bind(&NetClient_async::read_handler, this, _1, _2));
else
std::cout << "Finished read of " << bytes_read_so_far << " bytes." <<
std::endl;
}

void write_handler(const boost::system::error_code& ec, size_t
bytes_written) {
assert(bytes_written == sizeof(uint64_t));
sock.async_read_some(boost::asio::buffer(read_buffer),
boost::bind(&NetClient_async::read_handler, this, _1, _2));
}

void do_communication_work(uint64_t _bytes_to_read) {
bytes_read_so_far = 0;
bytes_to_read = _bytes_to_read;
read_size_param[0] = bytes_to_read;
sock.async_write_some(boost::asio::buffer(read_size_param),
boost::bind(&NetClient_async::write_handler, this, _1, _2));
}

void connect_handler(const boost::system::error_code& ec) {
// do_communication_work(4096*4096);
}

void resolve_handler(const boost::system::error_code& ec,
boost::asio::ip::tcp::resolver::iterator it) {
sock.async_connect(*it, boost::bind(&NetClient_async::connect_handler,
this, _1));
}

public:
NetClient_async() : resolver(io_service), sock(io_service) {}
void do_test() {
boost::asio::ip::tcp::resolver::query query("127.0.0.1", "8000");
resolver.async_resolve(query,
boost::bind(&NetClient_async::resolve_handler, this, _1, _2));
io_service.run();
// do_communication_work(4096*4096);
// io_service.run();
}
};

int main (int argc, const char * argv[])
{
NetClient_async client;
client.do_test();
}

If I uncomment the "do_communication_work" function in connect_handler(),
it works. If I instead uncomment the two lines in do_test instead, it does
not. I would appreciate any help/insight.

Daniel
Gruenke, Matt
2012-06-09 04:34:11 UTC
Permalink
If I instead uncomment the two lines in do_test instead, it does not.
But you're still leaving the 1st call to io_service::run() in place, are you? You need to reset the io_service before calling any of the run methods, except for the first time. However, I'd just remove the first call, entirely.


Matt



________________________________

From: Daniel Tracy [mailto:***@gmail.com]
Sent: Fri 6/8/2012 5:32 PM
To: asio-***@lists.sourceforge.net
Subject: [asio-users] asio: handler not being called after call toio_service.run()


I'm new to boost::asio, and I put together a small program to test my understanding of it. I have an asynchronously communicating client and server written below. I've narrowed down the problem to the following: On the client, if I initiate an async_write in the handler for async_connect, it works fine (the handler given to async_write gets called). If, however, I let it fall out of the io_service.run() call and later perform the async_write, the next call to io_service.run() just falls through.

Below is the code for the server (I've excluded error handling, etc).

#include <boost/asio.hpp>
#include <string>
#include <boost/bind.hpp>

class NetServer {
boost::asio::io_service io_service;
boost::asio::ip::tcp::endpoint endpoint;
boost::asio::ip::tcp::acceptor acceptor;
boost::asio::ip::tcp::socket sock;
boost::array<uint64_t, 1> read_buffer;
std::vector<char> write_buffer;

void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{
boost::asio::async_read(sock, boost::asio::buffer(read_buffer), boost::bind(&NetServer::read_request_handler, boost::ref(*this), _1, _2)); // read next request...
}

void read_request_handler(const boost::system::error_code& ec, std::size_t bytes_transferred)
{
assert( bytes_transferred == sizeof(uint64_t) );
uint64_t newSize = read_buffer[0];
uint64_t oldSize = write_buffer.size();
if( newSize > oldSize )
{
write_buffer.resize(newSize);
for( uint64_t i = oldSize; i < newSize; ++i )
write_buffer[i] = (char) (i % 128);
}
boost::asio::async_write(sock, boost::asio::buffer(&write_buffer[0], newSize), boost::bind(&NetServer::write_handler, boost::ref(*this), _1, _2));
}

void accept_connection_handler(const boost::system::error_code& ec)
{
boost::asio::async_read(sock, boost::asio::buffer(read_buffer), boost::bind(&NetServer::read_request_handler, boost::ref(*this), _1, _2));
}

public:
NetServer() : endpoint(boost::asio::ip::tcp::v4(), 8000), acceptor(io_service, endpoint), sock(io_service) {}
void run() {
acceptor.listen();
acceptor.async_accept(sock, boost::bind(&NetServer::accept_connection_handler, boost::ref(*this), _1));
io_service.run();
}
};

int main(int argc, const char * argv[])
{
NetServer nserve;
nserve.run();
}

And now the code for the client:

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
#include <vector>

class NetClient_async {
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver;
boost::asio::ip::tcp::socket sock;
boost::array<char, 131072> read_buffer;
boost::array<uint64_t, 1> read_size_param;
uint64_t bytes_to_read;
uint64_t bytes_read_so_far;

void read_handler(const boost::system::error_code& ec, size_t bytes_read) {
for( uint64_t i = 0; i < bytes_read; ++i )
assert(read_buffer[i] == char((bytes_read_so_far+i) % 128));
bytes_read_so_far += bytes_read;
if( bytes_read_so_far < bytes_to_read )
sock.async_read_some(boost::asio::buffer(read_buffer), boost::bind(&NetClient_async::read_handler, this, _1, _2));
else
std::cout << "Finished read of " << bytes_read_so_far << " bytes." << std::endl;
}

void write_handler(const boost::system::error_code& ec, size_t bytes_written) {
assert(bytes_written == sizeof(uint64_t));
sock.async_read_some(boost::asio::buffer(read_buffer), boost::bind(&NetClient_async::read_handler, this, _1, _2));
}

void do_communication_work(uint64_t _bytes_to_read) {
bytes_read_so_far = 0;
bytes_to_read = _bytes_to_read;
read_size_param[0] = bytes_to_read;
sock.async_write_some(boost::asio::buffer(read_size_param), boost::bind(&NetClient_async::write_handler, this, _1, _2));
}

void connect_handler(const boost::system::error_code& ec) {
// do_communication_work(4096*4096);
}

void resolve_handler(const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator it) {
sock.async_connect(*it, boost::bind(&NetClient_async::connect_handler, this, _1));
}

public:
NetClient_async() : resolver(io_service), sock(io_service) {}
void do_test() {
boost::asio::ip::tcp::resolver::query query("127.0.0.1", "8000");
resolver.async_resolve(query, boost::bind(&NetClient_async::resolve_handler, this, _1, _2));
io_service.run();
// do_communication_work(4096*4096);
// io_service.run();
}
};

int main (int argc, const char * argv[])
{
NetClient_async client;
client.do_test();
}

If I uncomment the "do_communication_work" function in connect_handler(), it works. If I instead uncomment the two lines in do_test instead, it does not. I would appreciate any help/insight.

Daniel
Daniel Tracy
2012-06-11 15:33:02 UTC
Permalink
Thank you very much. I did find it in the documentation after your reply as
well. I'll peruse that more thoroughly. I needed my test to make multiple
separate transmissions, so I went the reset() route.

Daniel
Post by Gruenke, Matt
**
If I instead uncomment the two lines in do_test instead, it does not.
But you're still leaving the 1st call to io_service::run() in place, are
you? You need to reset the io_service before calling any of the run
methods, except for the first time. However, I'd just remove the first
call, entirely.
Matt
------------------------------
*Sent:* Fri 6/8/2012 5:32 PM
*Subject:* [asio-users] asio: handler not being called after call
toio_service.run()
I'm new to boost::asio, and I put together a small program to test my
understanding of it. I have an asynchronously communicating client and
server written below. I've narrowed down the problem to the following: On
the client, if I initiate an async_write in the handler for async_connect,
it works fine (the handler given to async_write gets called). If, however,
I let it fall out of the io_service.run() call and later perform the
async_write, the next call to io_service.run() just falls through.
Below is the code for the server (I've excluded error handling, etc).
#include <boost/asio.hpp>
#include <string>
#include <boost/bind.hpp>
class NetServer {
boost::asio::io_service io_service;
boost::asio::ip::tcp::endpoint endpoint;
boost::asio::ip::tcp::acceptor acceptor;
boost::asio::ip::tcp::socket sock;
boost::array<uint64_t, 1> read_buffer;
std::vector<char> write_buffer;
void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{
boost::asio::async_read(sock, boost::asio::buffer(read_buffer),
boost::bind(&NetServer::read_request_handler, boost::ref(*this), _1, _2));
// read next request...
}
void read_request_handler(const boost::system::error_code& ec, std::size_t
bytes_transferred)
{
assert( bytes_transferred == sizeof(uint64_t) );
uint64_t newSize = read_buffer[0];
uint64_t oldSize = write_buffer.size();
if( newSize > oldSize )
{
write_buffer.resize(newSize);
for( uint64_t i = oldSize; i < newSize; ++i )
write_buffer[i] = (char) (i % 128);
}
boost::asio::async_write(sock, boost::asio::buffer(&write_buffer[0],
newSize), boost::bind(&NetServer::write_handler, boost::ref(*this), _1,
_2));
}
void accept_connection_handler(const boost::system::error_code& ec)
{
boost::asio::async_read(sock, boost::asio::buffer(read_buffer),
boost::bind(&NetServer::read_request_handler, boost::ref(*this), _1, _2));
}
NetServer() : endpoint(boost::asio::ip::tcp::v4(), 8000),
acceptor(io_service, endpoint), sock(io_service) {}
void run() {
acceptor.listen();
acceptor.async_accept(sock,
boost::bind(&NetServer::accept_connection_handler, boost::ref(*this), _1));
io_service.run();
}
};
int main(int argc, const char * argv[])
{
NetServer nserve;
nserve.run();
}
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
#include <vector>
class NetClient_async {
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver;
boost::asio::ip::tcp::socket sock;
boost::array<char, 131072> read_buffer;
boost::array<uint64_t, 1> read_size_param;
uint64_t bytes_to_read;
uint64_t bytes_read_so_far;
void read_handler(const boost::system::error_code& ec, size_t bytes_read) {
for( uint64_t i = 0; i < bytes_read; ++i )
assert(read_buffer[i] == char((bytes_read_so_far+i) % 128));
bytes_read_so_far += bytes_read;
if( bytes_read_so_far < bytes_to_read )
sock.async_read_some(boost::asio::buffer(read_buffer),
boost::bind(&NetClient_async::read_handler, this, _1, _2));
else
std::cout << "Finished read of " << bytes_read_so_far << " bytes." << std::endl;
}
void write_handler(const boost::system::error_code& ec, size_t
bytes_written) {
assert(bytes_written == sizeof(uint64_t));
sock.async_read_some(boost::asio::buffer(read_buffer),
boost::bind(&NetClient_async::read_handler, this, _1, _2));
}
void do_communication_work(uint64_t _bytes_to_read) {
bytes_read_so_far = 0;
bytes_to_read = _bytes_to_read;
read_size_param[0] = bytes_to_read;
sock.async_write_some(boost::asio::buffer(read_size_param),
boost::bind(&NetClient_async::write_handler, this, _1, _2));
}
void connect_handler(const boost::system::error_code& ec) {
// do_communication_work(4096*4096);
}
void resolve_handler(const boost::system::error_code& ec,
boost::asio::ip::tcp::resolver::iterator it) {
sock.async_connect(*it, boost::bind(&NetClient_async::connect_handler, this, _1));
}
NetClient_async() : resolver(io_service), sock(io_service) {}
void do_test() {
boost::asio::ip::tcp::resolver::query query("127.0.0.1", "8000");
resolver.async_resolve(query,
boost::bind(&NetClient_async::resolve_handler, this, _1, _2));
io_service.run();
// do_communication_work(4096*4096);
// io_service.run();
}
};
int main (int argc, const char * argv[])
{
NetClient_async client;
client.do_test();
}
If I uncomment the "do_communication_work" function in connect_handler(),
it works. If I instead uncomment the two lines in do_test instead, it does
not. I would appreciate any help/insight.
Daniel
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
asio-users mailing list
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio
Loading...