boost::buffer with boost::async_write - c++

I'm currently having a hard time with boost::asio, specially with the buffers in async_write operations.
When I want to write a packet, I use
async_write(sock_, boost::asio::buffer((char *)&t.getData(), sizeof(T)), boost::bind(&BoostTcpSocket::manageWrite, this, t, boost::asio::placeholders::error));
It works fine if i try to send one packet at the time. However if I make two followed call of async_write, it sends me twice the second packet. I have no problem with the packet life cycle.
I think the problem comes from the buffer, i'd like to have a packetQueue buffer instead of one packet buffer.
How can i do this ?
Thanks for your help
EDIT : here is more info about the code :
Here is how it works :
int BoostTcpSocket::manageWrite(Packet *t, const boost::system::error_code& error)
{
if (!er)
std::cout << "Success " << t.getData() << std::endl;
else
std::cout << "Error" << std::endl;
// delete t; => Packet LifeCycle isn't the problem here...
}
int main()
{
boost::asio::ip::tcp::socket sock_(io);
sock_.connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1", 8080));
Packet *p = new Packet("data1");
Packet *p2 = new Packet("data2");
sock_.async_write(boost::asio::buffer((char *)&p->getData(), sizeof(Packet::data)), boost::bind(&BoostTcpSocket::manageWrite, this, p, boost::asio::placeholders::error));
sock_.async_write(boost::asio::buffer((char *)&p2->getData(), sizeof(Packet::data)), boost::bind(&BoostTcpSocket::manageWrite, this, p2, boost::asio::placeholders::error));
io.run();
}
This code basically sends me twice the data "data2" even though the output on the server side std::cout is Success data1 Success data2...
EDIT : Apparently i was doing something wrong somewhere else because it is now working.. Thanks everybody for your time & help !

The data at &t.getData() must remain intact throughout the entire asynchronous operation. You must not overwrite the data there before receiving a call back to BoostUdpSocket::manageWrite with a success indication.

You have bound two times *p in your async_write(..) callbacks. This leads to double deletion!
See boost::bind(..., *p, ...)
sock_.async_write(boost::asio::buffer((char *)&p->getData(), sizeof(Packet::data)), boost::bind(&BoostTcpSocket::manageWrite, this, *p, boost::asio::placeholders::error));
sock_.async_write(boost::asio::buffer((char *)&p2->getData(), sizeof(Packet::data)), boost::bind(&BoostTcpSocket::manageWrite, this, *p, boost::asio::placeholders::error));
BTW: if you wannt to pass *p as reference, consider using boost::ref(..) or boost::cref(..).
EDIT:
The double delete is, i think, not your problem, but passing *p without boost::ref(..) is the problem - since you're deleting an object which is not heap allocated (because it is a copy!).
EDIT2:
Oh i see - you have the code corrcted in the meantime. Is there still a runtime error?

Related

Timeouts on read and writes

I have been searching for a way to cancel a Boost ASIO read or write operation if it takes over a certain amount of time. My server is sending out HTTP requests, and reading results from those requests, so I originally had coded it as a synchronous read/write, and if it took so long, I would just carry on and ignore the results when they came back. This caused a problem if a server went down, my server would open to many sockets, and would crash. So I decided that I wanted to cancel the read/write if there was too long of a delay, but apparently synchronous read/writes are not able to be canceled without destroying the thread they are running in, which I do not want to do. So I found a post about how to mimic a synchronous read/write with asynchronous calls and cancel a call on time out. This
is the post that I followed. I know this post is fairly old, so I am not sure if function calls have change since that version and the one I am working with(1.48), but this doesn't seem to be working quite right. Here is my code
bool connection::query_rtb(const std::string &request_information, std::string &reply_information)
{
try
{
boost::optional<boost::system::error_code> timer1_result, timer2_result, write_result, read_result;
boost::array<char,8192> buf;
buf.assign(0);
boost::asio::deadline_timer dt(io_service_);
dt.expires_from_now(boost::posix_time::milliseconds(100));
dt.async_wait(boost::bind(&connection::set_result, this, &timer1_result, _1, "timer1"));
boost::asio::async_write(socket_, boost::asio::buffer(request_information, request_information.size()), boost::bind(&connection::set_result, this, &write_result, _1, "write"));
io_service_.reset();
while(io_service_.run_one())
{
if(write_result)
{
dt.cancel();
}
else if(timer1_result)
{
socket_.cancel();
}
}
boost::asio::deadline_timer dt2(io_service_);
dt2.expires_from_now(boost::posix_time::milliseconds(3000));
dt2.async_wait(boost::bind(&connection::set_result, this, &timer2_result, _1, "timer2"));
boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
//socket_.async_receive(boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
io_service_.reset();
while(io_service_.run_one())
{
if(read_result)
{
dt2.cancel();
}
if(timer2_result)
{
socket_.cancel();
}
}
reply_information = buf.data();
std::cout << reply_information << std::endl;
return true;
}catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
void persistent_connection::set_result(boost::optional<boost::system::error_code> *a, boost::system::error_code ec, std::string t)
{
std::cout << t << std::endl;
a->reset(ec);
}
I was wondering if anyone see anything wrong with this code, or has any ideas on why it is not working. Currently the write seems to be fine, however the will not read until after the dt2 is done with it's timer. Please let me know if you need any more information, I will be glad to provide some.
Edit:
Seems like I got it working testing something I thought I previously tested. Using async_receive instead of async_read seems to have fixed whatever problem I was having. Any clue why this would cause I problem? I want to know if there is a problem with my logic or if that is how is async_read will usually act.
boost::array<char,8192> buf;
...
boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
You have instructed your program to read 8192 bytes from the socket. If switching the logic from using the async_read() free function to the async_receive() member function resolves this problem, consult the documentation
Remarks
The receive operation may not receive all of the requested number of
bytes. Consider using the async_read function if you need to ensure
that the requested amount of data is received before the asynchronous
operation completes.

Persistent ASIO connections

I am working on a project where I need to be able to use a few persistent to talk to different servers over long periods of time. This server will have a fairly high throughput. I am having trouble figuring out a way to setup the persistent connections correctly. The best way I could think of to do this is create a persistent connection class. Ideally I would connect to the server one time, and do async_writes as information comes into me. And read information as it comes back to me. I don't think I am structuring my class correctly though.
Here is what I have built right now:
persistent_connection::persistent_connection(std::string ip, std::string port):
io_service_(), socket_(io_service_), strand_(io_service_), is_setup_(false), outbox_()
{
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(ip,port);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ip::tcp::endpoint endpoint = *iterator;
socket_.async_connect(endpoint, boost::bind(&persistent_connection::handler_connect, this, boost::asio::placeholders::error, iterator));
io_service_.poll();
}
void persistent_connection::handler_connect(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
if(ec)
{
std::cout << "Couldn't connect" << ec << std::endl;
return;
}
else
{
boost::asio::socket_base::keep_alive option(true);
socket_.set_option(option);
boost::asio::async_read_until(socket_, buf_ ,"\r\n\r\n", boost::bind(&persistent_connection::handle_read_headers, this, boost::asio::placeholders::error));
}
}
void persistent_connection::write(const std::string &message)
{
write_impl(message);
//strand_.post(boost::bind(&persistent_connection::write_impl, this, message));
}
void persistent_connection::write_impl(const std::string &message)
{
outbox_.push_back(message);
if(outbox_.size() > 1)
{
return;
}
this->write_to_socket();
}
void persistent_connection::write_to_socket()
{
std::string message = "GET /"+ outbox_[0] +" HTTP/1.0\r\n";
message += "Host: 10.1.10.120\r\n";
message += "Accept: */*\r\n";
boost::asio::async_write(socket_, boost::asio::buffer(message.c_str(), message.size()), strand_.wrap(
boost::bind(&persistent_connection::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
}
void persistent_connection::handle_write(const boost::system::error_code& ec, std::size_t bytes_transfered)
{
outbox_.pop_front();
if(ec)
{
std::cout << "Send error" << boost::system::system_error(ec).what() << std::endl;
}
if(!outbox_.empty())
{
this->write_to_socket();
}
boost::asio::async_read_until(socket_, buf_ ,"\r\n\r\n",boost::bind(&persistent_connection::handle_read_headers, this, boost::asio::placeholders::error));
}
The first message I will send from this seems to send out fine, the server gets it, and responds with a valid response. I see two problem unfortunately:
1) My handle_write is never called after doing the async_write command, I have no clue why.
2) The program never reads the response, I am guessing this is related to #1, since asyn_read_until is not called until that function happens.
3) I was also wondering if someone could tell me why my commented out strand_.post call would not work.
I am guessing most of this has to due with my lack of knowledge of how I should be using my io_service, so if somebody could give me any pointer that would be greatly appreciated. And if you need any additional information, I would be glad to provide some more.
Thank you
Edit call to write:
int main()
{
persistent_connection p("10.1.10.220", "80");
p.write("100");
p.write("200");
barrier b(1,30000); //Timed mutex, waits for 300 seconds.
b.wait();
}
and
void persistent_connection::handle_read_headers(const boost::system::error_code &ec)
{
std::istream is(&buf_);
std::string read_stuff;
std::getline(is,read_stuff);
std::cout << read_stuff << std::endl;
}
The behavior described is the result of the io_service_'s event loop no longer being processed.
The constructor invokes io_service::poll() which will run handlers that are ready to run and will not block waiting for work to finish, where as io_service::run() will block until all work has finished. Thus, when polling, if the other side of the connection has not written any data, then no handlers may be ready to run, and execution will return from poll().
With regards to threading, if each connection will have its own thread, and the communication is a half-duplex protocol, such as HTTP, then the application code may be simpler if it is written synchronously. On the other hand, if it each connection will have its own thread, but the code is written asynchronously, then consider handling exceptions being thrown from within the event loop. It may be worth reading Boost.Asio's
effect of exceptions thrown from handlers.
Also, persistent_connection::write_to_socket() introduces undefined behavior. When invoking boost::asio::async_write(), it is documented that the caller retains ownership of the buffer and must guarantee that the buffer remains valid until the handler is called. In this case, the message buffer is an automatic variable, whose lifespan may end before the persistent_connection::handle_write handler is invoked. One solution could be to change the lifespan of message to match that of persistent_connection by making it a member variable.

Boost ASIO - How to write a console server 2

I'm trying to write a game server to run on Ubuntu Server (No GUI), and I'm having problems right at step 1. I'm new to C++, so please bear with me.
I need to be able to type commands to the server at any given point while it continues running. Since cin is a blocking input, that won't fly. I've dug around and it seems the way to go is to use Boost's ASIO library.
This answer comes incredibly close to fulfilling my needs, but I still need to know two more things:
1: The "command" passed from input seems to be limited to 1 char at a time. I need MUCH more than single key inputs, eg "shutdown", "say 'Hello World!'", "listPlayers -online", etc. I tried adapting the code to use string, instead of char:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <string>
using namespace boost::asio;
class Input : public boost::enable_shared_from_this<Input>
{
public:
typedef boost::shared_ptr<Input> Ptr;
public:
static void create(
io_service& io_service
)
{
Ptr input(
new Input( io_service )
);
input->read();
}
private:
explicit Input(
io_service& io_service
) :
_input( io_service )
{
_input.assign( STDIN_FILENO );
}
void read()
{
async_read(
_input,
boost::asio::buffer( &_command, sizeof(_command) ),
boost::bind(
&Input::read_handler,
shared_from_this(),
placeholders::error,
placeholders::bytes_transferred
));
}
void read_handler(
const boost::system::error_code& error,
size_t bytes_transferred
)
{
if ( error ) {
std::cerr << "read error: " << boost::system::system_error(error).what() << std::endl;
return;
}
if ( _command.compare( "\n" ) != 0 ) {
std::cout << "command: " << _command << std::endl;
}
this->read();
}
private:
posix::stream_descriptor _input;
std::string _command;
};
int main()
{
io_service io_service;
Input::create( io_service );
io_service.run();
}
However, this causes a segmentation error after a few characters of input, and pressing enter after entering any input no longer causes "command: " to appear. Is there a way to have this setup use string? I'm sure appending them to a separate string one character at a time will work, but I'd like to think this setup would work natively with entire strings.
2: (Edited for clarification) I need this non-blocking input to work in tandem with the rest of my server code. The question is: where does that code go? I call your attention to the main() function from above, modified to use a while loop, and call a mainLoop function:
bool loopControl = true;
int main()
{
io_service io_service;
Input::create( io_service );
// This loops continually until the server is commanded to shut down
while( loopControl )
{
io_service.run(); // Handles async input
mainLoop(); // Where my actual program resides
}
}
Even if everything else worked, control still won't ever reach mainLoop() under normal circumstances. In other words, io_service.run() is still blocking, defeating the entire purpose. This obviously isn't the correct way to implement io_service and/or mainLoop(); so what is?
My apologies if this has been done thousands of times, but apparently I'm not Googling the right phrases to bring up the results I'm looking for.
boost::asio::buffer does not directly support creating a mutable-buffer from an std::string, mainly because they are not guaranteed to be continuous in memory pre-C++11.
The way you are call it ((void*, size_t) overload), you will let the read overwrite the internals of std::string, which leads to your segfault. You should probably use one of the other overloads in this list: http://www.boost.org/doc/libs/1_50_0/doc/html/boost_asio/reference/buffer.html - most likely one for std::vector<char>, since you can easily copy that into a string when your read returns.
Now that problem is that you need to know beforehand how many chars you want to read, since your strings are of variable length. For that, you need to async_read the length separately before your read the actual contents. Then you resize the buffer (as I said, most likely std::vector<char>) and schedule a read of that length. Note that the sender can send both together, this is only complicated for reading from a stream... To summerize:
async_read your string length into some integer of fixed length
Resize the buffer for the content read appropriately
async_read your contents
As for your second question, it is not really clear what you want, but you might want to look into io_service::poll() if you want to do your own stuff while asio is running.
boost::asio::buffer( &_command, sizeof(_command) ) means that you want to overwrite 4 first bytes (or whatever sizeof(string) is) of _command object, but this is obviously not what you want. If you need an auto-resizing input buffer, use asio::streambuf instead.
io_service::run blocks the calling thread, so your mainLoop won't run. You can either execute io_service::run in a separate thread, or poll io_serivce manually, interleaving calls to run_one/poll_one (see the reference) with iterations of your own application loop.

Trying to use deadline_timer to add timeout to read_until

Maybe I am misunderstanding how things work, but I am trying to add a timeout to a read_until call, so I created a deadline_timer and started it before calling read_until, but the read_until still blocks everything, and the timer never gets activated. Am I doing it wrong? Below are some snippets from my code.
void MyClass::handle_timeout(const boost::system::error_code& error)
{
// Our deadline timer went off.
std::cout << "Deadline Timer was triggered." << std::endl;
Disconnect();
}
// Read some data.
void MyClass::ReadData(){
boost::asio::streambuf response;
deadline_.expires_from_now(boost::posix_time::seconds(DEFAULT_TIMEOUT));
deadline_.async_wait(boost::bind(&MyClass::handle_timeout, this, _1));
boost::asio::read_until(socket_,response,asString);
}
you're misunderstanding how things work. If you desire cancelability, you need to use the asynchronous methods such as
boost::asio::async_read_until(...);
instead of
boost::asio::read_until(socket_,response,asString);

Boost ASIO async_write "Vector iterator not dereferencable"

I've been working on an async boost server program, and so far I've got it to connect. However I'm now getting a "Vector iterator not dereferencable" error.
I suspect the vector gets destroyed or dereferenced before he packet gets sent thus causing the error.
void start()
{
Packet packet;
packet.setOpcode(SMSG_PING);
send(packet);
}
void send(Packet packet)
{
cout << "DEBUG> Transferring packet with opcode " << packet.GetOpcode() << endl;
async_write(m_socket, buffer(packet.write()), boost::bind(&Session::writeHandler, shared_from_this(), placeholders::error, placeholders::bytes_transferred));
}
void writeHandler(const boost::system::error_code& errorCode, size_t bytesTransferred)
{
cout << "DEBUG> Transfered " << bytesTransferred << " bytes to " << m_socket.remote_endpoint().address().to_string() << endl;
}
Start gets called once a connection is made.
packet.write() returns a uint8_t vector
Would it matter if I'd change
void send(Packet packet)
to
void send(Packet& packet)
Not in relation to this problem but performance wise.
All this depends on how your Packet class is implemented. How it is copied, .... Has the copy of Packet class do a deep copy or just a default copy? if it is a default copy and your class Packet is not a POD, this can be the reason, and you will need to do a deep copy.
In general it is better to pass a class parameter by const& so maybe you should try with
void send(Packet const& packet);
I have found a solution, as the vector would get destroyed I made a queue that contains the resulting packets and they get processed one by one, now nothing gets dereferenced so the problem is solved.
might want to change my queue to hold the packet class instead of the result but that's just a detail.