Boost ASIO - How to write a console server 2 - c++

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.

Related

Boost::asio::strand merges multiple handlers into one

I am currently using boost 1.70 and I was trying to implement io service loop to have a custom call between each invoked handle, and I couldn't get it to work. After some examination, I gained suspicion there are multiples handles executed in one call of "run_one" function. So I wrote a test code:
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/post.hpp>
#include <thread>
#include <mutex>
class StrandPost
{
private:
boost::asio::io_service service_;
boost::asio::io_service::work work_;
boost::asio::io_service::strand strand_;
std::thread module_thread_;
void Run() {
auto run_one = [this]() {
std::cout << " ---- Running one ----" << std::endl;
auto retval = service_.run_one();
return retval;
};
while (run_one());
std::cout << " ---- Ending run ----" << std::endl;
}
public:
StrandPost()
: service_()
, work_(service_)
, strand_(service_)
, module_thread_(&StrandPost::Run, this)
{}
~StrandPost() {
service_.stop();
if (module_thread_.joinable()) {
module_thread_.join();
}
}
void PlanOutput(const std::string& string) {
boost::asio::post(strand_,[string](){
std::cout << string <<std::endl;
});
// boost::asio::post(service_,[string](){
// std::cout << string <<std::endl;
// });
}
};
} // ----- end anonymous namespace -----
int main() {
StrandPost strand;
strand.PlanOutput("First message");
strand.PlanOutput("Second message");
strand.PlanOutput("Third message");
strand.PlanOutput("Fourth message");
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
And the output of that code confirmed my theory, because it was:
---- Running one ----
First message
---- Running one ----
Second message
Third message
Fourth message
---- Running one ----
---- Ending run ----
When using "io_service" directly, it works as expected, but when using "strand", after the first handle, multiple handles are executed as one.
So, the strand effectively merged several handlers into one.
My question is:
Is this bug or is this intentional? Am I doing something wrong?
If this is a bug, is it reported? Because I could not find a mention of this anywhere.
I'm fairly certain this is intentional. The strand itself is a queue of jobs, that only one thread at a time can perform.
When io_service::run_one runs, it causes the thread to run the strand ready queue. I believe the 'only one once' logic isn't passed through to the strand's processing loop. Think of it it this way, the io_service is told to do one handler, but the strand's handler runs several jobs in sequence before returning.
The best fix for your issue is, if you're going to have your own io_service in your class, is don't use the strand at all, and post directly to the io_service. Then you'll have the behavior you desire.
This is, indeed, as intended. The strand_executor_service pops all ready handlers on the same strand:
void strand_executor_service::run_ready_handlers(implementation_type& impl)
{
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl.get());
// Run all ready handlers. No lock is required since the ready queue is
// accessed only within the strand.
boost::system::error_code ec;
while (scheduler_operation* o = impl->ready_queue_.front())
{
impl->ready_queue_.pop();
o->complete(impl.get(), ec, 0);
}
}
It is quite obvious that this can have a great performance improving impact.
Well, its not that easy, since I also need to be guaranteed that handles posted for execution from a given thread will be executed in the order of posting. Preserving order between posts from different threads is irrelevant, however order of posts from a given thread must be preserved, and as far as I know, "io_service" does not guarantee this. But thanks for the answer, looking further into the boost implementation, it looks you are completely right. –
TStancek
6 hours ago
io_service does have the ordering guarantees of a strand (in fact, the strand's guarantees derive from that). In your case, there is - by definition - only one thread, so everything on the service will be in an implicit strand (see Why do I need strand per connection when using boost::asio?).
Summary
You can do without the strand for the example code in your question.
If your situation is more involved and you need the one-by-one message processing control, you would do better to have a task queue that implements this explicitly, instead of depending on implementation details.

`boost::asio::io_context` with `boost::process::async_pipe`: is there a way to run it reliably?

With Windows API, we can use pipes to forward process output and error streams, so we can read process output without any temporary files. Instead of this:
std::system("my_command.exe > out.tmp");
we can work much faster and without risk to generate a lot of forgotten temporary files (on system crash for example).
Linux has similar functionality. However, implementation of OS-specific code for each OS is time consuming and complex task, so it looks like good idea to use some portable solution.
boost::process claims to be such solution. However, it is fundamentally unreliable. See following sample program:
#include <fstream>
#include <iostream>
#include <memory>
#include <vector>
#include <boost/asio.hpp>
#include <boost/process.hpp>
void ReadPipe(boost::process::async_pipe& pipe, char* output_buffer, size_t output_buffer_size, boost::asio::io_context::strand& executor, std::ofstream& output_saver)
{
namespace io = boost::asio;
using namespace std;
io::async_read(
pipe,
io::buffer(
output_buffer,
output_buffer_size
),
io::bind_executor(executor, [&pipe, output_buffer, output_buffer_size, &executor, &output_saver](const boost::system::error_code& error, std::size_t bytes_transferred) mutable
{
// Save transferred data
if (bytes_transferred)
output_saver.write(output_buffer, bytes_transferred);
// Handle error
if (error)
{
if (error.value() == boost::asio::error::basic_errors::broken_pipe)
cout << "Child standard output is broken, so the process is most probably exited." << endl;
else
cout << "Child standard output read error occurred. " << boost::system::system_error(error).what() << endl;
}
else
{
//this_thread::sleep_for(chrono::milliseconds(50));
ReadPipe(pipe, output_buffer, output_buffer_size, executor, output_saver);
}
})
);
}
int main(void)
{
namespace io = boost::asio;
namespace bp = boost::process;
using namespace std;
// Initialize
io::io_context asio_context;
io::io_context::strand executor(asio_context);
bp::async_pipe process_out(asio_context);
char buffer[65535];
constexpr const size_t buffer_size = sizeof(buffer);
ofstream output_saver(R"__(c:\screen.png)__", ios_base::out | ios_base::binary | ios_base::trunc);
// Schedule to read standard output
ReadPipe(process_out, buffer, buffer_size, executor, output_saver);
// Run child
bp::child process(
bp::search_path("adb"),
bp::args({ "exec-out", "screencap", "-p" }),
bp::std_in.close(),
bp::std_out > process_out,
bp::std_err > process_out
);
asio_context.run();
process.wait();
output_saver.close();
// Finish
return 0;
}
This code works nice; it runs ADB, generates Android device screenshot and saves it with asynchronous pipe, so no temporary files are involved. This specific example saves the screenshot as a file, but in real application you can save data in memory, load and parse it.
I use ADB in my sample, because this tool gives good example of data that generated comparably slowly and that sent via USB or Wi-Fi (so also slowly), and the data size is comparably big (for full HD device with complex image the PNG file will be 1M+).
When I uncomment following line:
this_thread::sleep_for(chrono::milliseconds(50));
The pipe reading operation becomes completely unreliable. The program reads only part of data (of unpredictable size).
So, even so short delay as 50 milliseconds forces boost implementation of asynchronous pipe to fail.
It is not normal situation. What if CPU usage is near 100% (i. e. we are on highly loaded server)? What if the thread runs other ASIO jobs that may execute during 50 milliseconds or less? So, it is just easily reproducible implementation of fundamental boost ASIO bug: asynchronous pipe can not tolerate any delays when you started to read it; you have to call async_read again instantly after you received data, otherwise you are at risk to loose your data.
In practice when I use the same ASIO context to run multiple jobs (not only one async_read that reads process standard output), async_pipe fails in 50% of attempts to read 1M of data or more.
Does anyone know a workaround how to make async_pipe reliable and not to break connection if ASIO context runs async_read with very small delays required to run other jobs?

Asynchronously writing to a file in c++ unix

I have some long loop that I need to write some data to a file on every iteration. The problem is that writing to a file can be slow, so I would like to reduce the time this takes by doing the writing asynchronously.
Does anyone know a good way to do this? Should I be creating a thread that consumes whatever is put into it's buffer by writing it out ( in this case, a single producer, single consumer )?
I am interested mostly in solutions that don't involve anything but the standard library (C++11).
Before going into asynchronous writing, if you are using IOStreams you might want to try to avoid flushing the stream accidentally, e.g., by not using std::endl but rather using '\n' instead. Since writing to IOStreams is buffered this can improve performance quite a bit.
If that's not sufficient, the next question is how the data is written. If there is a lot of formatting going on, there is a chance that the actual formatting takes most of the time. You might be able to push the formatting off into a separate thread but that's quite different from merely passing off writing a couple of bytes to another thread: you'd need to pass on a suitable data structure holding the data to be formatted. What is suitable depends on what you are actually writing, though.
Finally, if writing the buffers to a file is really the bottleneck and you want to stick with the standard C++ library, it may be reasonable to have a writer thread which listens on a queue filled with buffers from a suitable stream buffer and writes the buffers to an std::ofstream: the producer interface would be an std::ostream which would send off probably fixed sized buffers either when the buffer is full or when the stream is flushed (for which I'd use std::flush explicitly) to a queue on which the other read listens. Below is a quick implementation of that idea using only standard library facilities:
#include <condition_variable>
#include <fstream>
#include <mutex>
#include <queue>
#include <streambuf>
#include <string>
#include <thread>
#include <vector>
struct async_buf
: std::streambuf
{
std::ofstream out;
std::mutex mutex;
std::condition_variable condition;
std::queue<std::vector<char>> queue;
std::vector<char> buffer;
bool done;
std::thread thread;
void worker() {
bool local_done(false);
std::vector<char> buf;
while (!local_done) {
{
std::unique_lock<std::mutex> guard(this->mutex);
this->condition.wait(guard,
[this](){ return !this->queue.empty()
|| this->done; });
if (!this->queue.empty()) {
buf.swap(queue.front());
queue.pop();
}
local_done = this->queue.empty() && this->done;
}
if (!buf.empty()) {
out.write(buf.data(), std::streamsize(buf.size()));
buf.clear();
}
}
out.flush();
}
public:
async_buf(std::string const& name)
: out(name)
, buffer(128)
, done(false)
, thread(&async_buf::worker, this) {
this->setp(this->buffer.data(),
this->buffer.data() + this->buffer.size() - 1);
}
~async_buf() {
std::unique_lock<std::mutex>(this->mutex), (this->done = true);
this->condition.notify_one();
this->thread.join();
}
int overflow(int c) {
if (c != std::char_traits<char>::eof()) {
*this->pptr() = std::char_traits<char>::to_char_type(c);
this->pbump(1);
}
return this->sync() != -1
? std::char_traits<char>::not_eof(c): std::char_traits<char>::eof();
}
int sync() {
if (this->pbase() != this->pptr()) {
this->buffer.resize(std::size_t(this->pptr() - this->pbase()));
{
std::unique_lock<std::mutex> guard(this->mutex);
this->queue.push(std::move(this->buffer));
}
this->condition.notify_one();
this->buffer = std::vector<char>(128);
this->setp(this->buffer.data(),
this->buffer.data() + this->buffer.size() - 1);
}
return 0;
}
};
int main()
{
async_buf sbuf("async.out");
std::ostream astream(&sbuf);
std::ifstream in("async_stream.cpp");
for (std::string line; std::getline(in, line); ) {
astream << line << '\n' << std::flush;
}
}
Search the web for "double buffering."
In general, one thread will write to one or more buffers. Another thread reads from the buffers, "chasing" the writing thread.
This may not make your program more efficient. Efficiency with files is achieved by writing in huge blocks so that the drive doesn't get a chance to spin down. One write of many bytes is more efficient than many writes of a few bytes.
This could be achieved by having the writing thread only write when the buffer content has exceeded some threshold like 1k.
Also research the topic of "spooling" or "print spooling".
You'll need to use C++11 since previous versions don't have threading support in the standard library. I don't know why you limit yourself, since Boost has some good stuff in it.

boost::asio::async_read_until not calling handler

I'm learning how to use Boost:asio library with Serial Port. I wrote some code using synchrous write and read and I now want to use asynchrous but it's not working.
Simple Example:
void readHandler(const boost::system::error_code&,std::size_t);
streambuf buf;
int main(int argc,char *argv[]){
io_service io;
serial_port port(io,PORT);
if(port.isopen()){
while(1){
// ... getting std::string::toSend from user ...
write(port,buffer(toSend.c_str(),toSend.size()));
async_read_until(port,buf,'\n',readHandler); // <= it's returning but not calling readHandler at all
}
port.close();
}
}
void readHandler(const boost::system::error_code& error,std::size_t bytes_transferred){
std::cout << "readHandler()" << std::endl;
//... reading from buf object and calling buf.consume(buf.size()) ...
}
async_read_until() it's returning but not calling readHandler(). If I change to synchrous read, it's reading from port OK. I also checking buf object each while loop and it's empty. What I'm doing wrong ??
As Janm has pointed out you need to call io.run for the async_read_until to work.
But...
You also need to convert the write over to an async_write, as the sync and async calls don't really work well together within asio. What you would need to do is the following:
setup first async_write
call io.run
in your write handler setup the async_read_until
in your read handler setup the next async_write
You need to call the run() method on the io_service for the callbacks to work. In your loop, you need io.run().

How do I make a function asynchronous in C++?

I want to call a function which will be asynchronous (I will give a callback when this task is done).
I want to do this in single thread.
This can be done portably with modern C++ or even with old C++ and some boost. Both boost and C++11 include sophisticated facilities to obtain asynchronous values from threads, but if all you want is a callback, just launch a thread and call it.
1998 C++/boost approach:
#include <iostream>
#include <string>
#include <boost/thread.hpp>
void callback(const std::string& data)
{
std::cout << "Callback called because: " << data << '\n';
}
void task(int time)
{
boost::this_thread::sleep(boost::posix_time::seconds(time));
callback("async task done");
}
int main()
{
boost::thread bt(task, 1);
std::cout << "async task launched\n";
boost::this_thread::sleep(boost::posix_time::seconds(5));
std::cout << "main done\n";
bt.join();
}
2011 C++ approach (using gcc 4.5.2, which needs this #define)
#define _GLIBCXX_USE_NANOSLEEP
#include <iostream>
#include <string>
#include <thread>
void callback(const std::string& data)
{
std::cout << "Callback called because: " << data << '\n';
}
void task(int time)
{
std::this_thread::sleep_for(std::chrono::seconds(time));
callback("async task done");
}
int main()
{
std::thread bt(task, 1);
std::cout << "async task launched\n";
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "main done\n";
bt.join();
}
As of C++11, plain c++ does have a concept of threads, but the most concise way to call a function asynchronously is to use the C++11 async command along with futures. This ends up looking a lot like the way you'd do the same thing in pthreads, but it's 100% portable to all OSes and platforms:
Say your function has a return value... int = MyFunc(int x, int y)
#include <future>
Just do:
// This function is called asynchronously
std::future<int> EventualValue = std::async(std::launch::async, MyFunc, x, y);
Catch? How do you know when it's done? (The barrier.)
Eventually, do:
int MyReturnValue = EventualValue.get(); // block until MyFunc is done
Note it's easy to do a parallel for loop this way - just create an array of futures.
You can't in plain C++. You'll need to use an OS-specific mechanism, and you need a point where execution is suspended in a way that allows the OS to execute the callback. E.g. for Windows, QueueUserAPC - the callback will be executed when you e.g. SleepEx or WaitForSingleObjectEx
The long answer involves implementing your own task scheduler and wrapping your "function" up into one or more tasks. I'm not sure you want the long answer. It certainly doesn't allow you to call something, completely forget about it, and then be notified when that thing is done; however if you are feeling ambitious, it will allow you to simulate coroutines on some level without reaching outside of standard C++.
The short answer is that this isn't possible. Use multiple threads or multiple processes. I can give you more specific information if you divulge what OS/platform you're developing for.
There are two bits to doing this.
Firstly, packing up the function call so that it can be executed later.
Secondly, scheduling it.
It is the scheduling which depends on other aspects of the implementation. If you know "when this task is done", then that's all you need - to go back and retrieve the "function call" and call it. So I am not sure this is necessarily a big problem.
The first part is then really about function objects, or even function pointers. The latter are the traditional callback mechanism from C.
For a FO, you might have:
class Callback
{
public:
virtual void callMe() = 0;
};
You derive from this and implement that as you see fit for your specific problem. The asyncronous event queue is then nothing more than a list<> of callbacks:
std::list<Callback*> asyncQ; // Or shared_ptr or whatever.
I'm not sure I understand what you want, but if it's how to make use of a callback: It works by defining a function pointer, like this (untested):
// Define callback signature.
typedef void (*DoneCallback) (int reason, char *explanation);
// A method that takes a callback as argument.
void doSomeWorkWithCallback(DoneCallback done)
{
...
if (done) {
done(1, "Finished");
}
}
//////
// A callback
void myCallback(int reason, char *explanation)
{
printf("Callback called with reason %d: %s", reason, explanation);
}
/////
// Put them together
doSomeWortkWithCallback(myCallback);
As others have said, you technically can't in plain C++.
However, you can create a manager that takes your task and does time-slicing or time scheduling; with each function call, the manager uses a timer to measure the amount of time the process took; if the process took less time than scheduled, and it thinks it can finish another call and use up the remaining time without going over, it can call it again; if the function does go over the alloted time, it means the function has less time next update to run. So, this will involve creating a somewhat complex system to handle it for you.
Or, if you have a specific platform in mind, you could use threading, or create another process to handle the work.