This is a SSCCE from my Boost.Asio project based on the examples. It took me about an hour to track the bug down to this:
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
class Connection {
public:
Connection(boost::asio::io_service& io_service) : socket(io_service) {}
private:
boost::asio::ip::tcp::socket socket;
};
class Server {
public:
Server() : signal_monitor(io_service) {
signal_monitor.add(SIGINT);
signal_monitor.add(SIGTERM);
signal_monitor.async_wait(
boost::bind(&Server::handle_signal_caught, this)
);
}
void run() {
// comment out the next line and there's no segfault
connection.reset(new Connection(io_service));
io_service.run();
}
private:
void handle_signal_caught() {
io_service.stop();
}
boost::shared_ptr<Connection> connection;
boost::asio::io_service io_service;
boost::asio::signal_set signal_monitor;
};
int main(int argc, char **argv) {
Server server;
server.run();
return 0;
}
When I send a signal (ctrl+C) the program segfaults instead of shutting down nicely. I've spent the last half hour looking at this, but I simply do not see why this would segfault, can any of you guys spot the issue?
I think I found out the issue. Note the declaration order of the members of Server:
boost::shared_ptr<Connection> connection;
boost::asio::io_service io_service;
boost::asio::signal_set signal_monitor;
Destruction order is done in the opposite order of declaration. This means that first signal_monitor, then io_service and finally connection get destroyed. But connection contains a boost::asio::ip::tcp::socket containing a reference to io_service, which got destroyed.
And indeed, this is pretty much what happening, and causes a segfault too:
int main(int argc, char **argv) {
auto io_service = new boost::asio::io_service();
auto socket = new boost::asio::ip::tcp::socket(*io_service);
delete io_service;
delete socket;
return 0;
}
Declaring connection after io_service solves the issue.
Damn
Related
I am building a application in qt where i am also creating a socket Server in a separate thread using boost.
Now when i close the GUI of the QT application i want the thread to be closed also.
But currently i am not able to understand how do we signal the thread to close when we close the GUI.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
cont.SetName("RootItem");
TreeModel* model = new TreeModel("RootElement", &cont);
WavefrontRenderer w(model);
w.show(); // Show the QT ui
boost::asio::io_service io_service;
server server1(io_service, 1980);
boost::thread t(boost::bind(&io_service::run, &io_service));
return a.exec();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "ConHandler.h"
#include "WavefrontRenderer.h"
class Server
{
private:
tcp::acceptor acceptor_;
void start_accept()
{
// socket
con_handler::pointer connection = con_handler::create(acceptor_.get_io_service());
// asynchronous accept operation and wait for a new connection.
acceptor_.async_accept(connection->socket(),
boost::bind(&Server::handle_accept, this, connection,
boost::asio::placeholders::error));
}
public:
//constructor for accepting connection from client
Server(boost::asio::io_service& io_service ) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 1980))
{
start_accept();
}
void handle_accept(con_handler::pointer connection, const boost::system::error_code& err)
{
if (!err) {
connection->start();
}
start_accept();
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
By saying stop thread you mean call stop method on io_service instance. Without this, destructor of boost::thread will be invoked on unfinished thread, what leads to UB.
All GUI events are processed in exec method. If you close all windows, this method ends. main ends as well, and at the end of main scope all local variables are destroyed.
So you can just make wrapper for lambda, which will be called at the end of main, and there you can call stop method. Then dtor of thread will work without any problems.
template<class F>
struct Cleaner {
Cleaner(F in) : f(in) {}
~Cleaner() { f(); }
F f;
};
template<class F>
Cleaner<F> makeCleaner(F f) {
return Cleaner<F>(f);
}
int main()
boost::asio::io_service io_service;
server server1(io_service, 1980);
boost::thread t(boost::bind(&io_service::run, &io_service));
auto raii = makeCleaner( [&](){ io_service.stop(); } );
return a.exec();
}
I would like to use a dedicated thread to receive udp data using asio library. An example code is given below.
#define ASIO_STANDALONE // we are using the stand aloe version of ASIO and Not Boost::ASIO
#include <iostream>
#include "include/asio.hpp"
#include <array>
#include <thread>
class UDPServer
{
public:
UDPServer( asio::io_service& ioService): m_socket(ioService)
{}
~UDPServer(){}
void listen(const int& port)
{
m_socket.open(asio::ip::udp::v4());
m_socket.bind(asio::ip::udp::endpoint(asio::ip::udp::v4(), port));
#define DEDICATED_THREAD_FLAG 1
#if DEDICATED_THREAD_FLAG
m_thread = std::thread( &UDPServer::receive, this);
std::cout<<"Thead Id in listen:"<<std::this_thread::get_id()<<std::endl;
m_thread.join();
#else
receive();
#endif
}
template<std::size_t SIZE>
void processReceivedData(const std::array<char, SIZE>& rcvdMessage,
const int& rcvdMessageSizeInBytes,
const std::error_code& error)
{
std::cout<<"Rcvd Message: "<<rcvdMessage.data()<<std::endl;
receive();
}
void receive()
{
std::cout<<"Thead Id in receive0:"<<std::this_thread::get_id()<<std::endl;
asio::ip::udp::endpoint m_udpRemoteEndpoint;
m_socket.async_receive_from(asio::buffer(recv_buffer, recv_buffer.size()/*NetworkBufferSize*/), m_udpRemoteEndpoint,
[this](std::error_code ec, std::size_t bytesReceived)
{
std::cout<<"Thead Id in receive1:"<<std::this_thread::get_id()<<std::endl;
processReceivedData(recv_buffer, bytesReceived, ec);
});
}
private:
asio::ip::udp::socket m_socket;
std::thread m_thread;
static const int NetworkBufferSize = 9000;
std::array<char, NetworkBufferSize> recv_buffer;
};
int main()
{
std::cout<<"Main Thead Id:"<<std::this_thread::get_id()<<std::endl;
asio::io_service m_ioService;
UDPServer myServer( m_ioService);
myServer.listen(12345); // starting the UDP server
std::cout<<"Program waiting.."<<std::endl;
m_ioService.run();
std::cout<<"Program ending.."<<std::endl;
}
A non dedicated thread version can be enable by changing DEDICATED_THREAD_FLAG to 0, which is working as expected.
However, when DEDICATED_THREAD_FLAG is set to 1, a new thread is starting and entering the "receive" function. But when a udp packet arrives, it is handled by only the main thread and not by the dedicated thread.
What is going wrong here?
The whole event-loop that handles the asynchronous calls is done by the io_server, which you run in the main thread.
Instead of running the receive function in the thread (it will return immediately anyway), you should run io_service::run.
I created a server using Boost ASIO. It builds fine but as soon as I run it, it gives segmentation fault. Can't really figure out this behaviour.
Also, I read that this may be due to me not initialising the io_service object explicitly. If, that's the case then how do I modify this code so that I don't have to pass io_service object from outside the class.
Below is my code:
#include <iostream>
#include <string>
#include <memory>
#include <array>
#include <boost/asio.hpp>
using namespace boost::asio;
//Connection Class
class Connection : public std::enable_shared_from_this<Connection>{
ip::tcp::socket m_socket;
std::array<char, 2056> m_acceptMessage;
std::string m_acceptMessageWrapper;
std::string m_buffer;
public:
Connection(io_service& ioService): m_socket(ioService) { }
virtual ~Connection() { }
static std::shared_ptr<Connection> create(io_service& ioService){
return std::shared_ptr<Connection>(new Connection(ioService));
}
std::string& receiveMessage() {
size_t len = boost::asio::read(m_socket, boost::asio::buffer(m_acceptMessage));
m_acceptMessageWrapper = std::string(m_acceptMessage.begin(), m_acceptMessage.begin() + len);
return m_acceptMessageWrapper;
}
void sendMessage(const std::string& message) {
boost::asio::write(m_socket, boost::asio::buffer(message));
}
ip::tcp::socket& getSocket(){
return m_socket;
}
};
//Server Class
class Server {
ip::tcp::acceptor m_acceptor;
io_service m_ioService ;
public:
Server(int port):
m_acceptor(m_ioService, ip::tcp::endpoint(ip::tcp::v4(), port)){ }
virtual ~Server() { }
std::shared_ptr<Connection> createConnection(){
std::shared_ptr<Connection> newConnection = Connection::create(m_ioService);
m_acceptor.accept(newConnection->getSocket());
return newConnection;
}
void runService() {
m_ioService.run();
}
};
int main(int argc, char* argv[]) {
Server s(5000);
auto c1 = s.createConnection();
//do soething
s.runService();
return 0;
}
You are facing initialisation order issues. In your class Server, you have declared m_acceptor before m_ioService and using the uninitialized io_service object to construct the acceptor.
Just reorder the declarations inside the class. Surprisingly clang did not give any warning for this.
class Server {
io_service m_ioService ;
ip::tcp::acceptor m_acceptor;
public:
Server(int port):
m_acceptor(m_ioService, ip::tcp::endpoint(ip::tcp::v4(), port)){ }
virtual ~Server() { }
std::shared_ptr<Connection> createConnection(){
std::shared_ptr<Connection> newConnection = Connection::create(m_ioService);
m_acceptor.accept(newConnection->getSocket());
return newConnection;
}
void runService() {
m_ioService.run();
}
};
All of the boost examples work until I try to implement the exact same thing myself. I'm starting to think there must be an order of creation or io_service ownership for things to block properly.
My server structure is as follows:
class Server {
public:
Server(unsigned short port)
: ioService_(), acceptor_(ioService_), socket_(ioService_) {
acceptClient(); // begin async accept
}
void start(); // runs ioService_.run();
private:
void acceptClient();
asio::io_service ioService_;
tcp::acceptor acceptor_;
tcp::socket socket_;
Cluster cluster_; // essentially just a connection manager
};
The acceptClient() function works like this:
void Server::acceptClient() {
acceptor_.async_accept(socket_, [this](const system::error_code& e){
if(!acceptor_.is_open()) return;
if(!e) {
cluster_.add(std::make_shared<Client>(std::move(socket_), cluster_));
}
acceptClient();
});
}
I'm not sure if you need an outline of the Client class since the server should run and block even with no clients.
The creation of the server goes as follows:
try {
Server server(port);
server.start(); // this calls the server's member io_service's run();
} catch (const std::exception& e) {
std::cerr << e.what(); << std::endl;
}
The problem is the server instantly closes after that call. The program starts and then exits with no errors. Is there something that io_service.run() relies on? e.g. some form of asynchronous link that I've forgotten? My learned this design from boost asio's http server design but I've worked it to fit my basic purposes. The problem is some boost examples establish a new member boost tcp::socket in the client itself rather than moving the server's to the client so I'm quite confused. They also tend to use boost's versions of std::bind instead of lambdas which etc.
So, can anyone give me a brief rundown on how to create a basic, stripped, async server since the boost examples are really confusing since the code conventions differ per example. I was wondering if anybody noticed anything straight away that would cause my server to instantly close.
Thanks.
I tested async_accept with the following code which sends Hello to clients connecting to the port. At least there is the creation of endpoint object, acceptor.open(endpoint.protocol()), acceptor.bind(endpoint) and acceptor.listen() calls that seem to be missing from your code.
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <string>
using namespace boost::asio;
void handle_accept(
io_service * ios,
ip::tcp::acceptor * acceptor,
ip::tcp::socket * socket,
const boost::system::error_code & error)
{
if (!error) {
std::string msg("Hello\n");
socket->send(buffer(msg, msg.length()));
ip::tcp::socket * temp = new ip::tcp::socket(*ios);
acceptor->async_accept(*temp,
boost::bind(handle_accept,
ios, acceptor, temp,
placeholders::error));
}
}
int main(void)
{
io_service ios;
ip::tcp::socket socket(ios);
ip::tcp::acceptor acceptor(ios);
ip::tcp::endpoint endpoint(ip::tcp::v4(), 1500);
acceptor.open(endpoint.protocol());
acceptor.set_option(ip::tcp::acceptor::reuse_address(true));
acceptor.bind(endpoint);
acceptor.listen();
acceptor.async_accept(socket,
boost::bind(handle_accept,
&ios, &acceptor, &socket,
placeholders::error));
ios.run();
/*
acceptor.accept(socket);
std::string msg("Hello\n");
socket.send(buffer(msg, msg.length()));
*/
}
A version with a Server class and a lambda as a argument for async_accept:
#include <boost/asio.hpp>
#include <functional>
#include <string>
using namespace boost::asio;
class Server {
public:
Server(unsigned short port) : ios(), acceptor(ios), socket(ios),
endpoint(ip::tcp::v4(), port) {
acceptor.open(endpoint.protocol());
acceptor.set_option(ip::tcp::acceptor::reuse_address(true));
acceptor.bind(endpoint);
acceptor.listen();
nsocket = &socket;
}
void run() {
std::function<void (const boost::system::error_code &)> f;
f = [&f, this] (const boost::system::error_code & error) {
if (!error) {
std::string msg("Hello\n");
nsocket->send(buffer(msg, msg.length()));
nsocket = new ip::tcp::socket(ios);
acceptor.async_accept(*nsocket, f);
}
};
acceptor.async_accept(socket, f);
ios.run();
}
protected:
io_service ios;
ip::tcp::acceptor acceptor;
ip::tcp::socket socket;
ip::tcp::endpoint endpoint;
ip::tcp::socket * nsocket;
};
int main(void)
{
Server srv(1500);
srv.run();
}
I have minor experience with c++ and facing some issue with boost-asio.
I want to rewrite standard boost-asio async-http-client example (http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/example/cpp03/http/client/async_client.cpp) in following way.
My goal is to have 2 classes;
AsyncHttpClient(that stores host and has member function that will send async calls to specified path).
AsyncHttpConnection (that takes io_service, host, path as parameters
and follows the flow specified in boost-asio async-http-client
example)
I have the following implementation
using boost::asio::ip::tcp;
class AsyncHttpConnection {
public:
AsyncHttpConnection(
boost::asio::io_service& io_service,
std::string host,
std::string path) : resolver_(io_service),
socket_(io_service),
host_(host),
path_(path)
{
tcp::resolver::query query(host_, "http");
resolver_.async_resolve(query,
boost::bind(&AsyncHttpConnection::handle_resolve,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
private:
std::string host_;
std::string path_;
tcp::resolver resolver_;
tcp::socket socket_;
boost::asio::streambuf request_;
boost::asio::streambuf response_;
void handle_resolve(
const boost::system::error_code& err,
tcp::resolver::iterator endpoint_iterator)
{
if (!err) {
// code here
} else {
std::cout << err.message() << std::endl; // GOT "Operation Canceled" here
}
}
// list of other handlers
};
class AsyncHttpClient {
public:
AsyncHttpClient(
boost::asio::io_service& io_service,
std::string host) : host_(host)
{
io_service_ = &io_service; // store address of io_service
}
void async_call(std::string path)
{
AsyncHttpConnection(*io_service_, host_, path);
}
private:
std::string host_;
boost::asio::io_service* io_service_; // pointer, because io_service is uncopyable;
};
int main(int argc, char* argv[])
{
boost::asio::io_service io_service;
AsyncHttpClient boost(io_service, "www.boost.org");
boost.async_call("/doc/libs/1_51_0/doc/html/boost_asio/example/http/client/async_client.cpp");
io_service.run();
}
I got an error "Operation Canceled" in this particular way;
If I instantiate AsyncHttpConnection in following way
int main(int argc, char* argv[])
{
boost::asio::io_service io_service;
AsyncHttpConnection(io_service, "www.boost.org", "path");
io_service.run();
}
I got everything working perfectly, I think the issue is using pointer to io_service. How can I solve this issue, if io_service object is uncopyable?
void async_call(std::string path) {
AsyncHttpConnection(*io_service_, host_, path);
}
The body constructs a temporary object of type AsyncHttpConnection. So, before the statement completes, the destructor for this type runs.
The default destructor does member-wise destruction. So it triggers the destructor tcp::resolver resolver_. The documentation for this class states that any pending asynchronous operation will be canceled on doing so.
In principle the "alternative" main has exactly the same problem (and indeed it fails with Operation canceled on my box). If it doesn't for you you're getting very fortunate timing of events.