multiple asio::async_write at the same time?

Apr 17, 2017 at 5:08pm
I'm using a tcp stream to reliably send messages, so I need each call to asio::async_write to finish before the next one starts.

I've discovered that simply creating a strand and using it to wrap calls to asio::async_write doesn't do the trick.
In other words multiple calls to asio::async_write will result in mixing of those messages.

Do I have to construct a messaging queue for storing those messages until the handlers for previous ones are called or is there a built in alternative?
Apr 17, 2017 at 7:08pm
as async_write documentation says, "The program must ensure that the stream performs no other write operations (such as async_write, the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes."

I had an application where the source of messages to send over TCP was asynchronous, and so indeed I wrote a message queue, from which the async_write's completion handler would grab the next message to call the next async_write with (it was before yield), that seems reasonable.
Apr 17, 2017 at 8:22pm
I'm assuming you're mentioning yield because it could be useful here?
Apr 17, 2017 at 10:12pm
I'm assuming you're mentioning yield because it could be useful here?

It doesn't change the semantics, it just makes async code look sane (and future-proof)
Apr 18, 2017 at 2:14am
Could you show me how and why to use it?
Apr 18, 2017 at 1:53pm
zoran404 wrote:
Could you show me how and why to use it?

Why - to escape the callback hell. How - boost has examples.

There are actually two kinds of coroutines there: stackful and stackless. Personally I like stackless (and that's where C++ moving too), but here's a stackful demo showing your multiple async writes, because it's better documented:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
std::vector<std::string> v{"foo\r\n", "bar\r\n", "baz\r\n", "xyzzy\r\n"};
int main()
{
  boost::asio::io_service io;
  boost::asio::spawn(io, [&](boost::asio::yield_context yield) {
  try {
    boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 12645);
    boost::asio::ip::tcp::socket sock(io);
    sock.async_connect(ep, yield);
    for (auto& str: v)
        boost::asio::async_write(sock, boost::asio::buffer(str), yield);
  } catch (std::exception& e) {
     std::cout << "caught " << e.what() << '\n';
  }
  });
  io.run();
}


to test, netcat in another terminal:
1
2
3
4
5
$ nc -l 12645
foo
bar
baz
xyzzy
Last edited on Apr 18, 2017 at 2:11pm
Apr 18, 2017 at 4:15pm
I can avoid callback simply by using spawn and passing yield instead? Damn that's nice.

Too bad I'm writing a server and instantiating a thread for each connection isn't practical.

Thanks for the example though!
Apr 18, 2017 at 6:41pm
You can also do that by using reenter and the pseudo-keyword yield: there's a demo of that approach in "http server v4" in boost docs: http://www.boost.org/doc/libs/1_63_0/doc/html/boost_asio/example/cpp03/http/server4/server.cpp

How are threads relevant? spawn doesn't create any.
Apr 19, 2017 at 2:53pm
Ok, I didn't notice that spawn doesn't create threads when I wrote that.
Either way I've already finished my server with the callbacks.
I would like to switch to coroutines though, simply because it's easier to write.
Not sure if there's any performance overhead to this?
Apr 19, 2017 at 2:56pm
CAN SOMEBODY HELP ME WITH THIS ?

Write a program that inputs a time from the console. The time should be in
the format "HH:MM AM" or "HH:MM PM". Hours may be one or two digits, for
example, "1:10 AM" or "11:30 PM". Your program should include a function
that takes a string parameter containing the time. This function should
convert the time into a four-digit military time based on a 24-hour clock.
For example, "1:10 AM" would output "0110 hours", "11:30 PM" would
output "2330 hours", and "12:15 AM" would output "0015 hours". The
function may either write the time to the console or return a string to be
written to the console by the main function.

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;

string convertToMilitaryTime(string time)
{
//gets colon and space position in the
// given time string
int colon = time.find(':');
int space = time.find(' ');

//extracts hours, minutes and meredian strings from the
// input time string
string hh = time.substr(0, colon);
string mm = time.substr(colon+1, space-colon-1);
string mer = time.substr(space+1);

//converts hours from string format to integer
int hours = atoi(hh.c_str());

// updating hours based on meredian
if(mer == "PM" &&hours != 12)
hours = hours + 12;
else if ( mer == "AM" &&hours == 12)
hours = 0;

//placing leading zero in hours if hour is one digit
if( hours >= 0 &&hours <= 9)
hh = "0";
else
hh = "";

//converring modified hours to string format
char H[5];
hh += itoa(hours,H,10) ;

//returns required output string
return hh + mm + " hours";
}

// main function
int main()
{
// inputs time in the form hh:mm AM/PM
string time;
cout << "Enter time (HH:MM AM) or (HH:MM PM): ";
getline(cin,time,'n');

//calls convertToMilitaryTime to conevert the given
//time into military time

string milTime = convertToMilitaryTime(time);

//displays to the console
cout << milTime << endl;
return 0;
}
Topic archived. No new replies allowed.