First i asked this Running a function on the main thread from a boost thread and passing parameters to that function
so now i am trying this:
The following is a console c++ project where i perfectly simulated my big project
TestServicePost.cpp
#include "stdafx.h"
#include "SomeClass.h"
int _tmain(int argc, _TCHAR* argv[])
{
SomeClass* s = new SomeClass();
while(true)
{
s->update();
}
return 0;
}
SomeClass.h
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <queue>
class ServiceNote
{
public:
std::string getType()
{
std::stringstream typeSS;
typeSS << "LamasaTech.MultiWall.PostNote." << (NoteType.compare("Normal") == 0 ? "Node" : "Header") << "." << Shape << "." << Colour;
return typeSS.str();
}
int Action;
int CNoteId;
std::string Colour;
int NoteId;
std::string NoteType;
int SessionId;
std::string Shape;
std::string Style;
std::string Text;
int X;
int Y;
};
class SomeClass
{
public:
SomeClass();
~SomeClass();
void update();
private:
std::queue<ServiceNote> pendingNotes;
void addToQueue(ServiceNote sn);
void pollService(boost::asio::io_service* svc);
int getMessage(boost::asio::io_service* svc, std::string sessionId, int messageId);
boost::thread servicePoller;
};
SomeClass.cpp
#include "stdafx.h"
#include "SomeClass.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/asio/signal_set.hpp>
#define POLL_SERVICE = 0;
#define POLLING_WAIT_TIME 1000
#define SAVE_SESSION_EVERY 1800000
SomeClass::SomeClass()
{
boost::asio::io_service io_servicePoller;
io_servicePoller.run();
servicePoller = boost::thread(boost::bind(&SomeClass::pollService, this, &io_servicePoller));
/*boost::asio::io_service io_sessionSaver;
boost::asio::signal_set signalsSaver(io_sessionSaver, SIGINT, SIGTERM);
signalsSaver.async_wait( boost::bind(&boost::asio::io_service::stop, &io_sessionSaver));
sessionSaver = boost::thread(&SomeClass::saveSessionEvery, io_sessionSaver);*/
}
SomeClass::~SomeClass()
{
}
void SomeClass::update()
{
while(!pendingNotes.empty())
{
ServiceNote sn = pendingNotes.front();
pendingNotes.pop();
}
}
void SomeClass::addToQueue(ServiceNote sn)
{
pendingNotes.push(sn);
}
void SomeClass::pollService(boost::asio::io_service* svc)
{
int messageId = 1;
while(true)
{
if(boost::this_thread::interruption_enabled() && boost::this_thread::interruption_requested())
return;
int currentId = messageId;
messageId = getMessage(svc, "49", messageId);
if(currentId == messageId)
boost::this_thread::sleep(boost::posix_time::milliseconds(POLLING_WAIT_TIME));
}
}
int SomeClass::getMessage(boost::asio::io_service* svc, std::string sessionId, int messageId)
{
try
{
boost::asio::io_service io_service;
// Get a list of endpoints corresponding to the server name.
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query("mw.rombus.com", "http");
boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
// Try each endpoint until we successfully establish a connection.
boost::asio::ip::tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " "/Service.svc/message/" << sessionId << "/" << messageId << " HTTP/1.0\r\n";
request_stream << "Host: " << "mw.rombus.com" << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
//std::cout << "Invalid response\n";
return messageId;
}
if (status_code != 200)
{
//std::cout << "Response returned with status code " << status_code << "\n";
return messageId;
}
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
std::string fullHeader = "";
while (std::getline(response_stream, header) && header != "\r")
fullHeader.append(header).append("\n");
// Write whatever content we already have to output.
std::string fullResponse = "";
if (response.size() > 0)
{
std::stringstream ss;
ss << &response;
fullResponse = ss.str();
try
{
boost::property_tree::ptree pt;
boost::property_tree::read_json(ss, pt);
ServiceNote sn;
sn.Action = pt.get<int>("Action");
sn.CNoteId = pt.get<int>("CNoteId");
sn.Colour = pt.get<std::string>("Colour");
sn.NoteId = pt.get<int>("NoteId");
sn.NoteType = pt.get<std::string>("NoteType");
sn.SessionId = pt.get<int>("SessionId");
sn.Shape = pt.get<std::string>("Shape");
sn.Style = pt.get<std::string>("Style");
sn.Text = pt.get<std::string>("Text");
sn.X = pt.get<int>("X");
sn.Y = pt.get<int>("Y");
svc->post(boost::bind(&SomeClass::addToQueue, this, sn));
//pendingNotes.push(sn);
}
catch (std::exception const& e)
{
std::string test = e.what();
//std::cerr << e.what() << std::endl;
}
messageId++;
}
// Read until EOF, writing data to output as we go.
std::string fullSth = "";
boost::system::error_code error;
while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error))
{
std::ostringstream ss;
ss << &response;
fullSth = ss.str();
}
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);
}
catch (std::exception& e)
{
std::string test = e.what();
std::cout << "Exception: " << e.what() << "\n";
}
return messageId;
}
but i get Unhandled exception at 0x771215de in TestServicePost.exe: 0xC0000005: Access violation writing location 0xcccccce4., right after this line executes:
svc->post(boost::bind(&SomeClass::addToQueue, this, sn));
I couldn't define io_service as a class member so i can use it in the destructor ~SomeClass(), would appreciate help on that too
If io_service.post is not the best solution for me please recommend something, as you can see i have a constructor, destructor and an update method who is called every tick, i tried using this and the queue alone but it wasn't thread safe, is there an easy thread safe FIFO to use ?
In SomeClass constructor you actually do the following:
Define a local io_service instance.
Call its run() member-function, which returns immediately, because io_service has no work.
Pass an address of the local object to another thread.
This certainly won't work.
Note that io_service::run() is a kind of "message loop", so it should block the calling thread. Don't call it in object constructor.
I figured out how to declare io_service as a class member:
boost::shared_ptr< boost::asio::io_service > io_servicePoller;
and in the constructor i did the following:
SomeClass::SomeClass()
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
io_servicePoller = io_service;
servicePoller = boost::thread(boost::bind(&SomeClass::pollService, this, io_servicePoller));
}
Some cleanup
SomeClass::~SomeClass()
{
servicePoller.interrupt();
io_servicePoller->stop();
servicePoller.join();
}
and in update i called run which adds the stuff into the queue, then reads them in the while loop
void SomeClass::update()
{
io_servicePoller->run();
io_servicePoller->reset();
while(!pendingNotes.empty())
{
ServiceNote sn = pendingNotes.front();
pendingNotes.pop();
}
}
and changed my members signature to void SomeClass::pollService(boost::shared_ptr< boost::asio::io_service > svc)
So what happens is:
The app starts
inits my class
my class makes a service and starts the thread
the thread fetches items from the service
the main thread checks the io service queue and exuted it
then it uses the queue
Thanks to Igor R. i couldn't have done it without him
and also http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=4 where i got how to make the shared pointer
Related
#include <functional>
#include <future>
#include <iostream>
class A
{
public:
int run(int a, const std::string& s)
{
std::cout << "a=" << a << ",s=" << s << std::endl;
return a+1;
}
};
int main()
{
A a;
auto f = std::bind(&A::run,&a,5,std::placeholders::_1);
std::packaged_task<int(const std::string&)> pt(std::move(f));
auto fut = std::async(std::move(pt),"test");
/// std::cout << fut.get() << std::endl; Does not compile
fut.get();
return 0;
}
Why fut.get() is returning void ? A::run is defined to return int and hence it should return int instead of void.
You are passing packaged_task instance to async, so return type for future is deduced based on:
std::packaged_task<R(Args...)>::operator()
void operator()( ArgTypes... args );
where void is returned.
If you want to get a result stored by packaged_task, you should read value stored by future returned by packaged_task::get_future:
A a;
auto f = std::bind(&A::run,&a,5,std::placeholders::_1);
std::packaged_task<int(const std::string&)> pt{std::move(f)};
std::future<int> fut = pt.get_future();
auto fut2 = std::async(std::move(pt),"test");
fut2.wait(); // wait until async's task is completed -> packaged_task was executed
std::cout << fut.get() << std::endl; // get result of packaged_task
Demo
I'm trying to download this link using an C++ apllication. But the it encountered exception:
terminate called after throwing an instance of 'boost::wrapexcept'
what(): body limit exceeded
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
I found out the problem is in http::write.
What on earth is going wrong? Does that mean I was just trying to download the whole file into the memory? If yes, can I continue using ssl::stream anymore? Or there's any alternative?
#ifndef __kernel_entry
#define __kernel_entry
#endif
#include <boost/asio.hpp>
#include <windows.h>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <boost/beast/http.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <iomanip>
#include <iostream>
void handle_batch(std::vector<size_t> params) {
std::mutex s_mx;
if (!params.empty()) {
// emulate some work, because I'm lazy
auto sum = std::accumulate(begin(params), end(params), 0ull);
// then wait some 100..200ms
{
using namespace std::chrono_literals;
std::mt19937 prng(std::random_device{}());
std::this_thread::sleep_for(
std::uniform_real_distribution<>(100,200)(prng)*1ms);
}
// simple thread id (thread::id displays ugly)
auto tid = std::hash<std::thread::id>{}(std::this_thread::get_id()) % 100;
// report results to stdout
std::lock_guard lk(s_mx); // make sure the output doesn't intermix
std::cout
<< "Thread #" << std::setw(2) << std::setfill('0') << tid
<< " Batch n:" << params.size()
<< "\tRange [" << params.front() << ".." << params.back() << "]"
<< "\tSum:" << sum
<< std::endl;
}
}
namespace net = boost::asio;
namespace ssl = net::ssl;
namespace beast = boost::beast;
namespace http = beast::http;
namespace process = boost::process;
using boost::system::error_code;
using boost::system::system_error;
using net::ip::tcp;
using stream = ssl::stream<tcp::socket>;
auto ssl_context() {
ssl::context ctx{ssl::context::sslv23};
return ctx;
}
void connect_https(stream& s, std::string const& host, tcp::resolver::iterator eps) {
net::connect(s.lowest_layer(), eps);
s.lowest_layer().set_option(tcp::no_delay(true));//dealt here
if (!SSL_set_tlsext_host_name(s.native_handle(), host.c_str())) {
throw system_error{ { (int)::ERR_get_error(), net::error::get_ssl_category() } };
}
s.handshake(stream::handshake_type::client);
}
auto get_request(std::string const& host, std::string const& path) {
using namespace http;
using std::cerr;
request<string_body> req;
req.version(11);cerr<<"__ver";
req.method(verb::get);cerr<<"__met";
req.target("https://" + host + path);cerr<<"__tar";
//req.set(field::user_agent, "test");
req.set(field::host, host);cerr<<"__set";
std::cerr << req << std::endl;
Sleep(1000);
return req;
}
int main() {
net::io_context io; // main thread does all io
net::thread_pool pool(6); // worker threads
// outside for lifetime
http::response_parser<http::buffer_body> response_reader;
beast::flat_buffer lookahead; // for the response_reader
std::array<char,512> buf{0}; // for download content
auto ctx = ssl_context();
ssl::stream<tcp::socket> s(io, ctx);
{ // synchronously write request
std::string host = "www.sfml-dev.org";
try{
connect_https(s, host, tcp::resolver{io}.resolve(host, "https"));
}catch(std::exception& e){std::cerr<<e.what()<<std::endl;}
http::write(s, get_request(host, "/files/SFML-2.5.1-windows-gcc-7.3.0-mingw-32-bit.zip"));
http::read_header(s, lookahead, response_reader);
std::cerr << "Headers: " << response_reader.get().base() << std::endl;
}//https://www.sfml-dev.org/files/SFML-2.5.1-windows-gcc-7.3.0-mingw-32-bit.zip
// now, asynchoronusly read contents
process::async_pipe pipe_to_zcat(io);
std::function<void(error_code, size_t)> receive_zip;
receive_zip = [&s, &response_reader, &pipe_to_zcat, &buf, &lookahead, &receive_zip](error_code ec, size_t /*ignore_this*/) {
auto& res = response_reader.get();
auto& body = res.body();
if (body.data) {
auto n = sizeof(buf) - body.size;
net::write(pipe_to_zcat, net::buffer(buf, n));
}
bool done = ec && !(ec == http::error::need_buffer);
done += response_reader.is_done();
if (done) {
std::cerr << "receive_zip: " << ec.message() << std::endl;
pipe_to_zcat.close();
} else {
body.data = buf.data();
body.size = buf.size();
http::async_read(s, lookahead, response_reader, receive_zip);
}
};
// kick off receive loop
receive_zip(error_code{}, 0);
process::async_pipe zcat_output(io);
process::child zcat(
process::search_path("zcat"),
process::std_in < pipe_to_zcat,
process::std_out > zcat_output,
process::on_exit([](int exitcode, std::error_code ec) {
std::cerr << "Child process exited with " << exitcode << " (" << ec.message() << ")\n";
}), io);
std::function<void(error_code, size_t)> receive_primes;
net::streambuf sb;
receive_primes = [&zcat_output, &sb, &receive_primes, &pool](error_code ec, size_t /*transferred*/) {
{
std::istream is(&sb);
size_t n = std::count(net::buffers_begin(sb.data()), net::buffers_end(sb.data()), '\n');
std::vector<size_t> batch(n);
std::copy_n(std::istream_iterator<size_t>(is), n, batch.begin());
is.ignore(1, '\n'); // we know a newline is pending, eat it to keep invariant
post(pool, std::bind(handle_batch, std::move(batch)));
}
if (ec) {
std::cerr << "receive_primes: " << ec.message() << std::endl;
zcat_output.close();
} else {
net::async_read_until(zcat_output, sb, "\n", receive_primes);
}
};
// kick off handler loop as well:
receive_primes(error_code{}, 0);
io.run();
pool.join();
}
I am trying to learn boost asio socket. there is one interesting example in boost web page which set a deadline time to monitor the timeout and change async io to sync io fashion. but when I remove the deadline timer the program stuck in while loop in write_line, I don't understand why the connection can be setup but the socket write is stuck. it seems that the writing never finished ,the handler never called so the "ec" never changed. Thank you in advance!!
#include <boost/asio/connect.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/write.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;
class client
{
public:
client()
: socket_(io_service_),
deadline_(io_service_)
{
deadline_.expires_from_now(boost::posix_time::seconds(10));
check_deadline(); // without this line which means without the this timer
//async_wait, the code stuck in write_line io_service_.run_one() loop .
}
void connect_handler(const boost::system::error_code& error,boost::system::error_code *er)
{
std::cerr<<"connect handler"<<std::endl;
*er = error;
std::cerr<<error<<std::endl;
}
void connect(const std::string& host, const std::string& service)
{
tcp::resolver::query query(host, service);
tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(query);
std::cerr<<"connect start"<<std::endl;
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_connect(socket_, iter, bind(&client::connect_handler,this,_1,&ec));
do
{io_service_.run_one();
}while (ec == boost::asio::error::would_block);
std::cerr<<"connect done"<<std::endl; // always works fine!
if (ec || !socket_.is_open())
throw boost::system::system_error(
ec ? ec : boost::asio::error::operation_aborted);
}
void write_handler(const boost::system::error_code& error, std::size_t size,boost::system::error_code* er )
{
std::cerr<<"write handler "<<std::endl;
*er=error;
std::cerr<<error<<std::endl;
}
void write_line(const std::string& line)
{
std::cerr<<"write start"<<std::endl;
std::string data = line + "\n";
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_write(socket_, boost::asio::buffer(data), bind(&client::write_handler,this,_1,_2,&ec));
do
{
io_service_.run_one(); //stuck here without "check_deadline();" in constructor.
}while (ec == boost::asio::error::would_block);
std::cerr<<"write done";
if (ec)
throw boost::system::system_error(ec);
}
private:
void check_deadline()
{
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
{
boost::system::error_code ignored_ec;
socket_.close(ignored_ec);
deadline_.expires_at(boost::posix_time::pos_infin);
throw boost::system::system_error(ignored_ec);
}
deadline_.async_wait(std::bind(&client::check_deadline, this));
}
boost::asio::io_service io_service_;
tcp::socket socket_;
deadline_timer deadline_;
};
int main()
{
try
{
client c,d;
c.connect("216.58.194.164", "80");// google IP.
c.write_line("test");
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Without comment out line "check_deadline();" in constructor the output is :
connect start
connect handler
system:0
connect done
write start
write handler
system:0
write done
when the line "check_deadline();" comment out in constructor, the output is :
connect start
connect handler
system:0
connect done
write start
and stuck there forever.
The whole point of that particular example is to have timeouts on blocking operations. This is why they use the async_* flavour of functions.
If you don't need that, don't use the async_* flavour at all:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
class client {
public:
client() : socket_(io_service_) { }
void connect(const std::string &host, const std::string &service) {
tcp::resolver::query query(host, service);
socket_.close();
boost::asio::connect(socket_, tcp::resolver(io_service_).resolve(query));
}
std::string read_line() {
boost::system::error_code ec;
boost::asio::read_until(socket_, input_buffer_, '\n', ec);
if (ec == boost::asio::error::eof)
socket_.close();
else if (ec)
throw boost::system::system_error(ec);
std::string line;
std::getline(std::istream(&input_buffer_), line);
return line;
}
void write_line(const std::string &line) {
std::string data = line + "\n";
boost::asio::write(socket_, boost::asio::buffer(data));
}
private:
boost::asio::io_service io_service_;
tcp::socket socket_;
boost::asio::streambuf input_buffer_;
};
int main(int argc, char *argv[]) {
try {
if (argc != 4) {
std::cerr << "Usage: blocking_tcp <host> <port> <message>\n";
return 1;
}
client c;
c.connect(argv[1], argv[2]);
boost::posix_time::ptime time_sent = boost::posix_time::microsec_clock::universal_time();
c.write_line(argv[3]);
for (;;) {
std::string line = c.read_line();
std::cout << "Received '" << line << "'\n";
if (line == argv[3])
break;
}
boost::posix_time::ptime time_received = boost::posix_time::microsec_clock::universal_time();
std::cout << "Round trip time: ";
std::cout << (time_received - time_sent).total_microseconds();
std::cout << " microseconds\n";
} catch (std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
That's a lot simpler. In fact, it's too simple in case the packets arriving contain more than 1 line at a time.
Instead of "fixing" the sample by re-complicating it, it can be ENORMOUSLY simpler:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
int main(int argc, char *argv[]) {
try {
if (argc != 4) {
std::cerr << "Usage: blocking_tcp <host> <port> <message>\n";
return 1;
}
tcp::iostream c(argv[1], argv[2]);
boost::posix_time::ptime time_sent = boost::posix_time::microsec_clock::universal_time();
c << argv[3] << "\n";
std::string line;
while (getline(c, line)) {
std::cout << "Received '" << line << "'\n";
if (line == argv[3])
break;
}
boost::posix_time::ptime time_received = boost::posix_time::microsec_clock::universal_time();
std::cout << "Round trip time: ";
std::cout << (time_received - time_sent).total_microseconds();
std::cout << " microseconds\n";
} catch (std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
I am trying to build up a client to get data via a specific protocol from a server.
I know that my code is not the best - but at the moment I am still experimenting with the basic functions of Boost ASIO.
I want to implement an read from TCP-Function which blocks until a specific amount of bytes have been received.
My Problem:
When I call boost::asio::read or boost::asio::write i geht following error:
error C2039: 'read_some' : is not a member of boost::shared_ptr'
I am working with VS2013 Professional, Boost 1.55.00 (precompiled).
Here is my Code: ( You can find the line by the comment "//HEEERE"
boost::mutex cout_lock;
int main()
{
// creating io_service
boost::shared_ptr<boost::asio::io_service> io_service(new boost::asio::io_service);
// creating work and assigning it to io_service
boost::shared_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(*io_service));
// creating strand and assigning it to io_service
boost::shared_ptr<boost::asio::io_service::strand> strand(new boost::asio::io_service::strand(*io_service));
// creating socket
boost::shared_ptr<boost::asio::ip::tcp::socket> socket(new boost::asio::ip::tcp::socket(*io_service));
try {
// creating resolver
boost::asio::ip::tcp::resolver resolver(*io_service);
// creating query
boost::asio::ip::tcp::resolver::query query(IPConfig_str, boost::lexical_cast<std::string>(IPConfig_PortNr));
// creating iterator
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
// creating endpoint
boost::asio::ip::tcp::endpoint endpoint = *iterator;
// connecting synchronously
socket->connect(endpoint);
}
catch(std::exception &ex) {
cout_lock.lock();
std::cout << "[main]:\t" << "Exception:" << ex.what() << std::endl;
cout_lock.unlock();
}
// Create Query
CommandCreator CMDCreator;
Command sendCommand;
CMDCreator.Create_fpga_GetSwVers(&sendCommand);
std::cout << std::endl;
std::cout << "SENT:" << std::endl;
for (int i = 0; i < sendCommand.length; i++)
{
std::cout << std::hex << std::setw(2) << std::setfill('0') << int(sendCommand.buffer[i]) << ", ";
}
std::cout << std::endl;
// Send Query
boost::system::error_code ec;
socket->async_send(boost::asio::buffer(sendCommand.buffer, sendCommand.length), boost::asio::transfer_all());
Sleep(300); // sleep 100 ms (at least 85 <- not stable!)
// Receive Answer - Header
Command receiveCommandHeader;
receiveCommandHeader.InitBuffer(4);
// Async
// socket->async_receive(boost::asio::buffer(receiveCommandHeader.buffer, receiveCommandHeader.length), 0, boost::bind(HandleRead, ec));
//HEEERE
boost::asio::read(socket, boost::asio::buffer(receiveCommandHeader.buffer, receiveCommandHeader.length), boost::asio::transfer_all(), ec);
//shutting down
socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
socket->close(ec);
io_service->stop();
return 0;
}
class Command
{
friend class CommandCreator; // TODO: is there a better and as simple method as a friend class?
public:
Command() : buffer(0)
{}
virtual ~Command()
{
delete[] buffer;
buffer = 0;
}
void InitBuffer(int const len)
{
this->length = len;
this->buffer = new uint8_t[len];
}
uint8_t* buffer;
int length;
};
Actually the problem is located at this part of boost in the file read.hpp, where async_read_some is called from 'stream_'.
void operator()(const boost::system::error_code& ec,
std::size_t bytes_transferred, int start = 0)
{
std::size_t n = 0;
switch (start_ = start)
{
case 1:
n = this->check_for_completion(ec, total_transferred_);
for (;;)
{
stream_.async_read_some(
boost::asio::buffer(buffer_ + total_transferred_, n),
BOOST_ASIO_MOVE_CAST(read_op)(*this));
return; default:
total_transferred_ += bytes_transferred;
if ((!ec && bytes_transferred == 0)
|| (n = this->check_for_completion(ec, total_transferred_)) == 0
|| total_transferred_ == boost::asio::buffer_size(buffer_))
break;
}
handler_(ec, static_cast<const std::size_t&>(total_transferred_));
}
}
Okey, I've just found the problem.
// creating socket
boost::shared_ptr<boost::asio::ip::tcp::socket> socket(new boost::asio::ip::tcp::socket(*io_service));
I created the socket as a pointer but all the interfaces of read, read_some and other boost-library functions require the object. Therefore adding the dereferencing operator did it:
boost::asio::async_read(*socket, boost::asio::buffer(receiveCommandHeader.buffer, receiveCommandHeader.length),
boost::asio::transfer_all(), boost::bind(HandleRead, ec));
With the following class
the header:
namespace msgSrv {
class endPoint {
public:
asio::ip::udp::endpoint ep;
endPoint(std::string ip, int port);
};
class msgSrv {
private:
asio::ip::udp::socket *asioSocket;
asio::io_service *asioIoService;
int listenPort;
boost::array<char, 1> rcvBuff;
asio::ip::udp::endpoint lastRcvdPcktEndp;
char * sbuff;
public:
boost::condition_variable cond;
boost::mutex mut;
msgSrv(int listenPort);
virtual ~msgSrv();
void start();
void pckRcvd(const asio::error_code& error, std::size_t bytes_transferred);
void sendTo(const char* buff, int len, endPoint ep);
void sendHnd(const asio::error_code& error, std::size_t bytes_transferred);
};
}
the .cpp
#include "msgSrv.h"
namespace msgSrv {
endPoint::endPoint(const std::string ip, int port) {
asio::ip::address addr = asio::ip::address::from_string(ip);
ep = asio::ip::udp::endpoint(addr, port);
}
msgSrv::msgSrv(int listenPort) {
// TODO Auto-generated constructor stub
this->listenPort = listenPort;
try {
asioIoService = new asio::io_service();
asioSocket = new asio::ip::udp::socket(*asioIoService,
asio::ip::udp::endpoint(asio::ip::udp::v4(), listenPort)); //new asio::ip::udp::socket_(*asioIoService, udp::endpoint(udp::v4(), listenPort));
} catch (std::exception &e) {
std::cerr << "Error initializing ioservice or socket:" << e.what();
}
asioIoService->run();
}
msgSrv::~msgSrv() {
// TODO Auto-generated destructor stub
delete asioIoService;
delete asioSocket;
}
void msgSrv::start() {
asioSocket->async_receive_from(asio::buffer(rcvBuff), lastRcvdPcktEndp,
boost::bind(&msgSrv::pckRcvd, this, asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
void msgSrv::pckRcvd(const asio::error_code& error,
std::size_t bytes_transferred) {
std::cout << "Rcvd! " << lastRcvdPcktEndp.address().to_string() << ":"
<< lastRcvdPcktEndp.port() << "\n";
}
void msgSrv::sendTo(const char* buff, int len, endPoint ep) {
sbuff = new char[len];
mempcpy(sbuff, buff, len);
asioSocket->async_send_to(asio::buffer(sbuff, len), ep.ep, boost::bind(
&msgSrv::sendHnd, this, asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
void msgSrv::sendHnd(const asio::error_code& error,
std::size_t bytes_transferred) {
std::cout << "Snt!\n";
delete sbuff;
}
}
and the following "main" file:
int main()
{
msgSrv::msgSrv aa(4450);
aa.start();
msgSrv::endPoint ep("127.0.0.1", 4450);
std::string a("Prova!");
int len = a.length();
aa.sendTo(a.c_str(), len, ep);
std::cout << "sent...\n";
std::cout << "notified...\n";
}
all I get is:
terminate called after throwing an instance of 'asio::system_error'
what(): mutex: Invalid argument
sent...
notified...
What's wrong?? I tried even to put a while(1) in the main, to see if something happens... I even tried to put a condition in the main that is unlocked by the receive handler... all remains locked... So what??? No idea!
I don't see you actually locking any muxtex, so that error is strange.
However your problem is to calling asioIoService->run() inside the constructor, witch fall in infinite loop. The solution is to create a new boost::thread, witch call asioIoService->run() itself. This thread will be processing all jobs. You may also call asio::io_service::run() with more then one thread, to get processing on more then one job at the same time.
m_thread = new boost::thread(boost::bind(&asio::io_service::run,asioIoService));
Calling asioIoService->stop() will force exit of asio::io_service::run(), thus closing the thread. You must join this thread to ensure that thread terminates before destroying asioIoService pointer in the destructor of your msgSrv class.