Daniel Tracy
2012-06-08 21:32:20 UTC
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
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