Hi, Asio users.
BOOST_ASIO_DISABLE_EPOLL doesn't help - select-based reactor shows similar behavior.
Marat Abrarov.
-----Original Message-----
Sent: Friday, July 22, 2011 11:03 PM
Subject: Re: [asio-users] A strange issue on Linux, but on Windows works perfectly
Hi, Dmitry.
Post by Dmitry TimoshenkoI added a simple check before write to the socket, the behaviour is not
changed, the issue is present anyway.
The link is the same
http://64.186.158.86:8400/asio-sample/socket_test2.zip
~~~~~~~~~~~~~~~~~~~~~~~~
///////////////////////////////////////////////////////////////////////////////
// main.cpp
//
// Pos hardware project. Socket test.
//
// Entry point.
//
// 2011, (c) Dmitry Timoshenko.
#include "auto_sence.hpp"
#include <boost/asio.hpp>
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <iostream>
#include <stdexcept>
#include <string>
#include <memory>
#include <vector>
#include <sstream>
#define SMART_DEBUG_OUT(expr) cout << std::dec << __FILE__ << "[" << __LINE__ << "]: " << expr <<
std::endl;
#if defined (POSHW_WIN)
# include <tchar.h>
# include <conio.h>
#elif defined (POSHW_UNIX)
# include <stdio.h>
# include <unistd.h>
#endif // POSHW_WIN
using std::cout;
using std::endl;
using std::string;
using boost::asio::ip::tcp;
using boost::asio::ip::address;
using boost::asio::io_service;
using boost::lexical_cast;
using boost::posix_time::milliseconds;
namespace
{
/** For debug purpose. */
template <typename IterT>
std::string to_string(const std::string& prefix, IterT first, IterT last)
{
std::stringstream ss;
ss << prefix << "[" << std::hex << std::showbase;
for ( ; first != last; )
{
ss << (static_cast<unsigned int>(*first++) & 0xff);
ss << (first == last? "]": ", ");
}
ss << std::dec;
return ss.str();
}
class server;
//////////////////////////////////////////////////////////////////////////
// session
class session
{
//////////////////////////////////////////////////////////////////////////
// interface
/** Disconnect error. */
class disconnect_error : public std::runtime_error
{
explicit disconnect_error(const std::string& what): std::runtime_error(what) { /* empty */ }
};
server& _server;
/** Constructs a session object. */
_socket(ioservice),
_connected(false),
_is_writing(false),
_server(the_server)
{
_local_buffer.assign(local_bufsz, 0);
}
/** Closes connection and destroys an object. */
~session(void) { disconnect(); }
/** Process outgoing messages and receives incoming if there are. */
void process(void)
{
// at first, process errors
process_errors();
}
/** Returns reference to internal asio socket. */
boost::asio::ip::tcp::socket& socket(void) { return _socket; }
/** Initializes the session. */
void initiate(void)
{
clear_state();
start_read();
connected(true);
}
/** Session remote endpoint. */
tcp::endpoint remote_endpoint(void) const
{
boost::system::error_code err;
return socket().remote_endpoint(err);
}
/** Session local endpoint. */
tcp::endpoint local_endpoint(void) const
{
boost::system::error_code err;
return socket().local_endpoint(err);
}
//////////////////////////////////////////////////////////////////////////
// private stuff
enum { local_bufsz = 0x1000 };
typedef std::vector<char> local_buffer_type;
typedef std::string out_buffer_type;
typedef boost::shared_ptr<out_buffer_type> out_buffer_ptr;
void disconnect(void)
{
if (connected())
{
connected(false);
boost::system::error_code err;
socket().shutdown(tcp::socket::shutdown_both, err);
SMART_DEBUG_OUT("[session]: SOCKET SHUTDOWN; [remote: " << remote_endpoint() << "; local: " <<
local_endpoint() <<
"; error_code: " << err << "; " << err.message() << "]");
}
close_socket();
}
//-----------------------------------------------------------------------------
void close_socket(void)
{
if (socket().is_open())
{
boost::system::error_code err;
socket().close(err);
SMART_DEBUG_OUT("[session]: SOCKET CLOSED; [remote: " << remote_endpoint() << "; local: " <<
local_endpoint() <<
"; error_code: " << err << "; " << err.message() << "]");
}
}
//-----------------------------------------------------------------------------
void clear_state(void)
{
connected(false);
_read_error.clear();
_write_error.clear();
_buffer.clear();
_local_buffer.assign(local_bufsz, 0);
}
//-----------------------------------------------------------------------------
void process_errors(void)
{
// handle any channel error
handle_ch_error();
}
//-----------------------------------------------------------------------------
void handle_ch_error(void)
{
if (_read_error || _write_error)
{
const boost::system::error_code error = _read_error? _read_error: _write_error;
_read_error.clear();
_write_error.clear();
SMART_DEBUG_OUT("[session]: Channel error; [" << error << ", " << error.message() << "]");
handle_disconnected(error, "Channel error");
}
}
//-----------------------------------------------------------------------------
void handle_disconnected(const boost::system::error_code& reason, const std::string& what);
//////////////////////////////////////////////////////////////////////////
// boost asio manipulators
void start_read(void)
{
_socket.async_read_some(boost::asio::buffer(_local_buffer),
boost::bind(&session::asio_read_handler, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
//-----------------------------------------------------------------------------
void start_write(const string& s)
{
if (!is_writing())
{
is_writing(true);
BOOST_ASSERT(!s.empty() && " - Output buffer can't be empty");
out_buffer_ptr out_buf(new out_buffer_type(s));
// start asio async write
boost::asio::async_write(_socket, boost::asio::buffer(*out_buf),
boost::bind(&session::asio_write_handler, this, boost::asio::placeholders::error, out_buf));
}
}
//////////////////////////////////////////////////////////////////////////
// boost asio handlers
void asio_read_handler(const boost::system::error_code& error, size_t n)
{
SMART_DEBUG_OUT("[session]: Async read completed invoked");
_read_error = error;
if (error)
{
SMART_DEBUG_OUT("[session]: Read channel error; [" << error << "; " << error.message() << "]");
} else
{
// get data
BOOST_ASSERT(n <= _local_buffer.size() && " - Buffer overrun detected");
// at first, start next read operation anyway
start_read();
const size_t sz = std::min(n, _local_buffer.size());
const string s(_local_buffer.begin(), _local_buffer.begin() + sz);
_buffer += s;
SMART_DEBUG_OUT("[session]: Incoming data '" << s << "' = " <<
to_string(lexical_cast<string>(unsigned(sz))
+ " byte(s) ", _local_buffer.begin(), _local_buffer.begin() + sz));
start_write(s);
}
SMART_DEBUG_OUT("[session]: Async read completed finished");
process_errors();
}
//-----------------------------------------------------------------------------
void asio_write_handler(const boost::system::error_code& error, out_buffer_ptr buf)
{
SMART_DEBUG_OUT("[session]: Async write completed invoked");
_write_error = error;
is_writing(false);
if (error)
{
SMART_DEBUG_OUT("[session]: Write channel error; [" << error << "; " << error.message() << "]");
} else
{
SMART_DEBUG_OUT(to_string(string("[session]: Sent ") + lexical_cast<string>(unsigned(buf-
+ " byte(s) ", buf->begin(), buf->end()));
}
SMART_DEBUG_OUT("[session]: Async write completed finished");
process_errors();
}
//-----------------------------------------------------------------------------
bool connected(void) const { return socket().is_open() && _connected; }
void connected(bool c) { _connected = c; }
const boost::asio::ip::tcp::socket& socket(void) const { return _socket; }
bool is_writing(void) const { return _is_writing; }
void is_writing(bool writing) { _is_writing = writing; }
boost::asio::ip::tcp::socket _socket;
std::string _buffer;
local_buffer_type _local_buffer;
bool _connected;
bool _is_writing;
//////////////////////////////////////////////////////////////////////////
// error flags
boost::system::error_code _read_error;
boost::system::error_code _write_error;
}; // class session
//////////////////////////////////////////////////////////////////////////
// server
class server
{
//////////////////////////////////////////////////////////////////////////
// interface
/** Constructs a server object. */
_acceptor(ioservice()),
_session(ioservice(), *this)
{
create_listening_socket();
start_accept();
}
/** Serve iteration.
*
* Serves the underlying socket and process the incoming data.
*/
void serve(void) { process_iteration(); }
//////////////////////////////////////////////////////////////////////////
// private stuff
// types
typedef std::auto_ptr<boost::asio::io_service::work> service_work_ptr;
void process_iteration(void)
{
try
{
ioservice().poll();
_session.process();
}
catch (const session::disconnect_error& e)
{
SMART_DEBUG_OUT("[server]: Disconnect error exception; [what: " << e.what() << "]");
handle_disconnected(e.what());
}
catch (const std::exception& e)
{
SMART_DEBUG_OUT("[server]: An UNEXPECTED std::exception [what: " << e.what() << "]");
BOOST_ASSERT(!"An UNEXPECTED std::exception!");
}
catch (...)
{
SMART_DEBUG_OUT("[server]: An UNKNOWN UNEXPECTED exception!");
BOOST_ASSERT(!"An UNKNOWN UNEXPECTED exception!");
}
}
//-----------------------------------------------------------------------------
void start_accept(void)
{
acceptor().async_accept(_session.socket(),
boost::bind(&server::asio_accept_handler, this, boost::asio::placeholders::error));
}
//-----------------------------------------------------------------------------
void create_listening_socket(void)
{
if (!acceptor().is_open())
{
boost::system::error_code err;
acceptor().open(tcp::v4(), err);
SMART_DEBUG_OUT("[server]: Listening socket is opened " << "[" << err << "; " << err.message()
<< "]");
acceptor().bind(tcp::endpoint(address(), 5555), err);
SMART_DEBUG_OUT("[server]: Listening socket is bind " << acceptor().local_endpoint() << " [" <<
err << "; " <<
err.message() << "]");
acceptor().listen();
}
}
//-----------------------------------------------------------------------------
void destroy_listening_socket(void)
{
if (acceptor().is_open())
{
boost::system::error_code err;
acceptor().close(err);
SMART_DEBUG_OUT("[server]: Listening socket is closed [" << err << "; " << err.message() <<
"]");
}
}
//-----------------------------------------------------------------------------
void asio_accept_handler(const boost::system::error_code& error)
{
SMART_DEBUG_OUT("[server]: Asio accept handler invoked; [" << error << ", " << error.message() <<
"]");
if (error)
{
SMART_DEBUG_OUT("[server]: Accept error [" << error << ", " << error.message() << "]");
} else
{
// only one connection is allowed
destroy_listening_socket();
_session.initiate();
SMART_DEBUG_OUT("[server]: Client accepted; [remote ep = " << _session.remote_endpoint() << ";
local ep = " <<
_session.local_endpoint() << "]");
}
SMART_DEBUG_OUT("[server]: Asio accept handler finished; [" << error << ", " << error.message() <<
"]");
}
//-----------------------------------------------------------------------------
void handle_disconnected(const string& reason)
{
SMART_DEBUG_OUT("[server]: Disconnected handler invoked [" << reason << "]");
try
{
create_listening_socket();
start_accept();
}
catch (...)
{
SMART_DEBUG_OUT("[server]: Handle disconnected rose an UNEXPECTED exception");
BOOST_ASSERT(!"Handle disconnected rose an UNEXPECTED exception");
}
}
//-----------------------------------------------------------------------------
boost::asio::ip::tcp::acceptor& acceptor(void) { return _acceptor; }
boost::asio::io_service& ioservice(void) { return _ioservice; }
service_work_ptr _work;
io_service _ioservice;
tcp::acceptor _acceptor;
session _session;
}; // class server
//-----------------------------------------------------------------------------
void session::handle_disconnected(const boost::system::error_code& reason, const std::string& what)
{
SMART_DEBUG_OUT("[session]: Disconnected handler invoked; [" << reason << ", " << reason.message()
<< "]");
disconnect();
//throw disconnect_error(what + "[" + reason.message() + "]");
_server.handle_disconnected(what + "[" + reason.message() + "]");
}
//////////////////////////////////////////////////////////////////////////
// auxiliary
void print_help(void)
{
cout << "\nEcho test server, try telnet localhost 5555\n"
<< "press 'q' to quit (and strike enter on Linux)"
<< endl;
}
//------------------------------------------------------------------------
bool _is_working = true;
bool is_working(void) { return _is_working; }
void stop(void) { _is_working = false; }
//------------------------------------------------------------------------
#if defined (POSHW_WIN)
char get_char(void)
{
return char(_getch());
}
#elif defined (POSHW_UNIX)
char get_char(void)
{
return char(getchar());
}
#endif // POSHW_UNIX
//------------------------------------------------------------------------
void serving(void)
{
try
{
print_help();
server srv;
while (is_working())
{
srv.serve();
boost::this_thread::sleep(milliseconds(10));
}
} catch (const std::exception& e)
{
SMART_DEBUG_OUT("Error occurred: [" << e.what() << "]");
}
}
} // unnamed namespace
//------------------------------------------------------------------------
#if defined (POSHW_WIN)
int _tmain(int /*argc*/, _TCHAR* []/*argv[]*/)
#elif defined (POSHW_UNIX)
int main(int /*argc*/, char** /*argv*/)
#endif // POSHW_UNIX
{
boost::thread th(&serving);
for (char c = 0; c != 'q' && c != 'Q'; c = get_char())
{
;
}
stop();
th.join();
return 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~
It seems that there is an issue with acceptor::async_accept in Boost.Asio (at least in Boost 1.46, try
to check your
example with Boost 1.47). When the second async_accept is done within the completion handler (in
io_service::poll) all
works fine (see above code). And when the second async_accept is called outside of the
io_service::poll, accept
completion handler isn't called.
This issue really should be reported to the author of the Boost.Asio. Try to simplify your example and
open an issue at
Asio bug tracker (http://sourceforge.net/tracker/?group_id=122478&atid=694037).
Regards,
Marat Abrarov.
------------------------------------------------------------------------------
10 Tips for Better Web Security
Web security, SSL, hacker attacks & Denial of Service (DoS), private keys,
security Microsoft Exchange, secure Instant Messaging, and much more.
http://www.accelacomm.com/jaw/sfnl/114/51426210/
_______________________________________________
asio-users mailing list
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio